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

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

1.18    ! djm         1: /* $OpenBSD: ssh-pkcs11-client.c,v 1.17 2020/10/18 11:32:02 djm Exp $ */
1.1       markus      2: /*
                      3:  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
1.12      djm         4:  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
1.1       markus      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20: #include <sys/time.h>
                     21: #include <sys/socket.h>
                     22:
                     23: #include <stdarg.h>
                     24: #include <string.h>
                     25: #include <unistd.h>
                     26: #include <errno.h>
1.18    ! djm        27: #include <limits.h>
1.5       djm        28:
1.12      djm        29: #include <openssl/ecdsa.h>
1.5       djm        30: #include <openssl/rsa.h>
1.1       markus     31:
                     32: #include "pathnames.h"
                     33: #include "xmalloc.h"
1.9       markus     34: #include "sshbuf.h"
1.1       markus     35: #include "log.h"
                     36: #include "misc.h"
1.9       markus     37: #include "sshkey.h"
1.1       markus     38: #include "authfd.h"
                     39: #include "atomicio.h"
                     40: #include "ssh-pkcs11.h"
1.9       markus     41: #include "ssherr.h"
1.1       markus     42:
                     43: /* borrows code from sftp-server and ssh-agent */
                     44:
1.18    ! djm        45: /*
        !            46:  * Maintain a list of ssh-pkcs11-helper subprocesses. These may be looked up
        !            47:  * by provider path or their unique EC/RSA METHOD pointers.
        !            48:  */
        !            49: struct helper {
        !            50:        char *path;
        !            51:        pid_t pid;
        !            52:        int fd;
        !            53:        RSA_METHOD *rsa_meth;
        !            54:        EC_KEY_METHOD *ec_meth;
        !            55:        int (*rsa_finish)(RSA *rsa);
        !            56:        void (*ec_finish)(EC_KEY *key);
        !            57:        size_t nrsa, nec; /* number of active keys of each type */
        !            58: };
        !            59: static struct helper **helpers;
        !            60: static size_t nhelpers;
        !            61:
        !            62: static struct helper *
        !            63: helper_by_provider(const char *path)
        !            64: {
        !            65:        size_t i;
        !            66:
        !            67:        for (i = 0; i < nhelpers; i++) {
        !            68:                if (helpers[i] == NULL || helpers[i]->path == NULL ||
        !            69:                    helpers[i]->fd == -1)
        !            70:                        continue;
        !            71:                if (strcmp(helpers[i]->path, path) == 0)
        !            72:                        return helpers[i];
        !            73:        }
        !            74:        return NULL;
        !            75: }
        !            76:
        !            77: static struct helper *
        !            78: helper_by_rsa(const RSA *rsa)
        !            79: {
        !            80:        size_t i;
        !            81:        const RSA_METHOD *meth;
        !            82:
        !            83:        if ((meth = RSA_get_method(rsa)) == NULL)
        !            84:                return NULL;
        !            85:        for (i = 0; i < nhelpers; i++) {
        !            86:                if (helpers[i] != NULL && helpers[i]->rsa_meth == meth)
        !            87:                        return helpers[i];
        !            88:        }
        !            89:        return NULL;
        !            90:
        !            91: }
        !            92:
        !            93: static struct helper *
        !            94: helper_by_ec(const EC_KEY *ec)
        !            95: {
        !            96:        size_t i;
        !            97:        const EC_KEY_METHOD *meth;
        !            98:
        !            99:        if ((meth = EC_KEY_get_method(ec)) == NULL)
        !           100:                return NULL;
        !           101:        for (i = 0; i < nhelpers; i++) {
        !           102:                if (helpers[i] != NULL && helpers[i]->ec_meth == meth)
        !           103:                        return helpers[i];
        !           104:        }
        !           105:        return NULL;
        !           106:
        !           107: }
1.1       markus    108:
                    109: static void
1.18    ! djm       110: helper_free(struct helper *helper)
        !           111: {
        !           112:        size_t i;
        !           113:        int found = 0;
        !           114:
        !           115:        if (helper == NULL)
        !           116:                return;
        !           117:        if (helper->path == NULL || helper->ec_meth == NULL ||
        !           118:            helper->rsa_meth == NULL)
        !           119:                fatal_f("inconsistent helper");
        !           120:        debug3_f("free helper for provider %s", helper->path);
        !           121:        for (i = 0; i < nhelpers; i++) {
        !           122:                if (helpers[i] == helper) {
        !           123:                        if (found)
        !           124:                                fatal_f("helper recorded more than once");
        !           125:                        found = 1;
        !           126:                }
        !           127:                else if (found)
        !           128:                        helpers[i - 1] = helpers[i];
        !           129:        }
        !           130:        if (found) {
        !           131:                helpers = xrecallocarray(helpers, nhelpers,
        !           132:                    nhelpers - 1, sizeof(*helpers));
        !           133:                nhelpers--;
        !           134:        }
        !           135:        free(helper->path);
        !           136:        EC_KEY_METHOD_free(helper->ec_meth);
        !           137:        RSA_meth_free(helper->rsa_meth);
        !           138:        free(helper);
        !           139: }
        !           140:
        !           141: static void
        !           142: helper_terminate(struct helper *helper)
        !           143: {
        !           144:        if (helper == NULL) {
        !           145:                return;
        !           146:        } else if (helper->fd == -1) {
        !           147:                debug3_f("already terminated");
        !           148:        } else {
        !           149:                debug3_f("terminating helper for %s; "
        !           150:                    "remaining %zu RSA %zu ECDSA",
        !           151:                    helper->path, helper->nrsa, helper->nec);
        !           152:                close(helper->fd);
        !           153:                /* XXX waitpid() */
        !           154:                helper->fd = -1;
        !           155:                helper->pid = -1;
        !           156:        }
        !           157:        /*
        !           158:         * Don't delete the helper entry until there are no remaining keys
        !           159:         * that reference it. Otherwise, any signing operation would call
        !           160:         * a free'd METHOD pointer and that would be bad.
        !           161:         */
        !           162:        if (helper->nrsa == 0 && helper->nec == 0)
        !           163:                helper_free(helper);
        !           164: }
        !           165:
        !           166: static void
        !           167: send_msg(int fd, struct sshbuf *m)
1.1       markus    168: {
                    169:        u_char buf[4];
1.9       markus    170:        size_t mlen = sshbuf_len(m);
                    171:        int r;
1.1       markus    172:
1.18    ! djm       173:        if (fd == -1)
        !           174:                return;
1.9       markus    175:        POKE_U32(buf, mlen);
1.1       markus    176:        if (atomicio(vwrite, fd, buf, 4) != 4 ||
1.10      markus    177:            atomicio(vwrite, fd, sshbuf_mutable_ptr(m),
1.9       markus    178:            sshbuf_len(m)) != sshbuf_len(m))
1.1       markus    179:                error("write to helper failed");
1.9       markus    180:        if ((r = sshbuf_consume(m, mlen)) != 0)
1.17      djm       181:                fatal_fr(r, "consume");
1.1       markus    182: }
                    183:
                    184: static int
1.18    ! djm       185: recv_msg(int fd, struct sshbuf *m)
1.1       markus    186: {
                    187:        u_int l, len;
1.9       markus    188:        u_char c, buf[1024];
                    189:        int r;
1.1       markus    190:
1.18    ! djm       191:        sshbuf_reset(m);
        !           192:        if (fd == -1)
        !           193:                return 0; /* XXX */
1.1       markus    194:        if ((len = atomicio(read, fd, buf, 4)) != 4) {
                    195:                error("read from helper failed: %u", len);
                    196:                return (0); /* XXX */
                    197:        }
1.9       markus    198:        len = PEEK_U32(buf);
1.1       markus    199:        if (len > 256 * 1024)
                    200:                fatal("response too long: %u", len);
                    201:        /* read len bytes into m */
                    202:        while (len > 0) {
                    203:                l = len;
                    204:                if (l > sizeof(buf))
                    205:                        l = sizeof(buf);
                    206:                if (atomicio(read, fd, buf, l) != l) {
                    207:                        error("response from helper failed.");
                    208:                        return (0); /* XXX */
                    209:                }
1.9       markus    210:                if ((r = sshbuf_put(m, buf, l)) != 0)
1.17      djm       211:                        fatal_fr(r, "sshbuf_put");
1.1       markus    212:                len -= l;
                    213:        }
1.9       markus    214:        if ((r = sshbuf_get_u8(m, &c)) != 0)
1.17      djm       215:                fatal_fr(r, "parse type");
1.9       markus    216:        return c;
1.1       markus    217: }
                    218:
                    219: int
                    220: pkcs11_init(int interactive)
                    221: {
1.18    ! djm       222:        return 0;
1.1       markus    223: }
                    224:
                    225: void
                    226: pkcs11_terminate(void)
                    227: {
1.18    ! djm       228:        size_t i;
        !           229:
        !           230:        debug3_f("terminating %zu helpers", nhelpers);
        !           231:        for (i = 0; i < nhelpers; i++)
        !           232:                helper_terminate(helpers[i]);
1.1       markus    233: }
                    234:
                    235: static int
1.12      djm       236: rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
1.1       markus    237: {
1.14      djm       238:        struct sshkey *key = NULL;
                    239:        struct sshbuf *msg = NULL;
                    240:        u_char *blob = NULL, *signature = NULL;
1.9       markus    241:        size_t blen, slen = 0;
                    242:        int r, ret = -1;
1.18    ! djm       243:        struct helper *helper;
1.1       markus    244:
1.18    ! djm       245:        if ((helper = helper_by_rsa(rsa)) == NULL || helper->fd == -1)
        !           246:                fatal_f("no helper for PKCS11 key");
        !           247:        debug3_f("signing with PKCS11 provider %s", helper->path);
1.1       markus    248:        if (padding != RSA_PKCS1_PADDING)
1.14      djm       249:                goto fail;
                    250:        key = sshkey_new(KEY_UNSPEC);
                    251:        if (key == NULL) {
1.17      djm       252:                error_f("sshkey_new failed");
1.14      djm       253:                goto fail;
                    254:        }
                    255:        key->type = KEY_RSA;
                    256:        RSA_up_ref(rsa);
                    257:        key->rsa = rsa;
                    258:        if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
1.17      djm       259:                error_fr(r, "encode key");
1.14      djm       260:                goto fail;
1.9       markus    261:        }
                    262:        if ((msg = sshbuf_new()) == NULL)
1.17      djm       263:                fatal_f("sshbuf_new failed");
1.9       markus    264:        if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
                    265:            (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
                    266:            (r = sshbuf_put_string(msg, from, flen)) != 0 ||
                    267:            (r = sshbuf_put_u32(msg, 0)) != 0)
1.17      djm       268:                fatal_fr(r, "compose");
1.18    ! djm       269:        send_msg(helper->fd, msg);
1.9       markus    270:        sshbuf_reset(msg);
1.1       markus    271:
1.18    ! djm       272:        if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) {
1.9       markus    273:                if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
1.17      djm       274:                        fatal_fr(r, "parse");
1.9       markus    275:                if (slen <= (size_t)RSA_size(rsa)) {
1.1       markus    276:                        memcpy(to, signature, slen);
                    277:                        ret = slen;
                    278:                }
1.4       djm       279:                free(signature);
1.1       markus    280:        }
1.14      djm       281:  fail:
                    282:        free(blob);
                    283:        sshkey_free(key);
1.9       markus    284:        sshbuf_free(msg);
1.1       markus    285:        return (ret);
                    286: }
                    287:
1.18    ! djm       288: static int
        !           289: rsa_finish(RSA *rsa)
        !           290: {
        !           291:        struct helper *helper;
        !           292:
        !           293:        if ((helper = helper_by_rsa(rsa)) == NULL)
        !           294:                fatal_f("no helper for PKCS11 key");
        !           295:        debug3_f("free PKCS11 RSA key for provider %s", helper->path);
        !           296:        if (helper->rsa_finish != NULL)
        !           297:                helper->rsa_finish(rsa);
        !           298:        if (helper->nrsa == 0)
        !           299:                fatal_f("RSA refcount error");
        !           300:        helper->nrsa--;
        !           301:        debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
        !           302:            helper->path, helper->nrsa, helper->nec);
        !           303:        if (helper->nrsa == 0 && helper->nec == 0)
        !           304:                helper_terminate(helper);
        !           305:        return 1;
        !           306: }
        !           307:
1.12      djm       308: static ECDSA_SIG *
                    309: ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
                    310:     const BIGNUM *rp, EC_KEY *ec)
                    311: {
1.14      djm       312:        struct sshkey *key = NULL;
                    313:        struct sshbuf *msg = NULL;
                    314:        ECDSA_SIG *ret = NULL;
1.12      djm       315:        const u_char *cp;
1.14      djm       316:        u_char *blob = NULL, *signature = NULL;
1.12      djm       317:        size_t blen, slen = 0;
1.14      djm       318:        int r, nid;
1.18    ! djm       319:        struct helper *helper;
1.12      djm       320:
1.18    ! djm       321:        if ((helper = helper_by_ec(ec)) == NULL || helper->fd == -1)
        !           322:                fatal_f("no helper for PKCS11 key");
        !           323:        debug3_f("signing with PKCS11 provider %s", helper->path);
1.14      djm       324:        nid = sshkey_ecdsa_key_to_nid(ec);
                    325:        if (nid < 0) {
1.17      djm       326:                error_f("couldn't get curve nid");
1.14      djm       327:                goto fail;
1.12      djm       328:        }
1.14      djm       329:
                    330:        key = sshkey_new(KEY_UNSPEC);
                    331:        if (key == NULL) {
1.17      djm       332:                error_f("sshkey_new failed");
1.14      djm       333:                goto fail;
                    334:        }
                    335:        key->ecdsa = ec;
                    336:        key->ecdsa_nid = nid;
                    337:        key->type = KEY_ECDSA;
                    338:        EC_KEY_up_ref(ec);
                    339:
                    340:        if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
1.17      djm       341:                error_fr(r, "encode key");
1.14      djm       342:                goto fail;
1.12      djm       343:        }
                    344:        if ((msg = sshbuf_new()) == NULL)
1.17      djm       345:                fatal_f("sshbuf_new failed");
1.12      djm       346:        if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
                    347:            (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
                    348:            (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 ||
                    349:            (r = sshbuf_put_u32(msg, 0)) != 0)
1.17      djm       350:                fatal_fr(r, "compose");
1.18    ! djm       351:        send_msg(helper->fd, msg);
1.12      djm       352:        sshbuf_reset(msg);
                    353:
1.18    ! djm       354:        if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) {
1.12      djm       355:                if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
1.17      djm       356:                        fatal_fr(r, "parse");
1.12      djm       357:                cp = signature;
                    358:                ret = d2i_ECDSA_SIG(NULL, &cp, slen);
                    359:                free(signature);
                    360:        }
                    361:
1.14      djm       362:  fail:
                    363:        free(blob);
                    364:        sshkey_free(key);
1.12      djm       365:        sshbuf_free(msg);
                    366:        return (ret);
                    367: }
                    368:
1.18    ! djm       369: static void
        !           370: ecdsa_do_finish(EC_KEY *ec)
        !           371: {
        !           372:        struct helper *helper;
        !           373:
        !           374:        if ((helper = helper_by_ec(ec)) == NULL)
        !           375:                fatal_f("no helper for PKCS11 key");
        !           376:        debug3_f("free PKCS11 ECDSA key for provider %s", helper->path);
        !           377:        if (helper->ec_finish != NULL)
        !           378:                helper->ec_finish(ec);
        !           379:        if (helper->nec == 0)
        !           380:                fatal_f("ECDSA refcount error");
        !           381:        helper->nec--;
        !           382:        debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
        !           383:            helper->path, helper->nrsa, helper->nec);
        !           384:        if (helper->nrsa == 0 && helper->nec == 0)
        !           385:                helper_terminate(helper);
        !           386: }
1.12      djm       387:
                    388: /* redirect private key crypto operations to the ssh-pkcs11-helper */
                    389: static void
1.18    ! djm       390: wrap_key(struct helper *helper, struct sshkey *k)
1.12      djm       391: {
1.18    ! djm       392:        debug3_f("wrap %s for provider %s", sshkey_type(k), helper->path);
        !           393:        if (k->type == KEY_RSA) {
        !           394:                RSA_set_method(k->rsa, helper->rsa_meth);
        !           395:                if (helper->nrsa++ >= INT_MAX)
        !           396:                        fatal_f("RSA refcount error");
        !           397:        } else if (k->type == KEY_ECDSA) {
        !           398:                EC_KEY_set_method(k->ecdsa, helper->ec_meth);
        !           399:                if (helper->nec++ >= INT_MAX)
        !           400:                        fatal_f("EC refcount error");
        !           401:        } else
1.17      djm       402:                fatal_f("unknown key type");
1.18    ! djm       403:        k->flags |= SSHKEY_FLAG_EXT;
        !           404:        debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
        !           405:            helper->path, helper->nrsa, helper->nec);
1.12      djm       406: }
                    407:
1.1       markus    408: static int
1.18    ! djm       409: pkcs11_start_helper_methods(struct helper *helper)
1.1       markus    410: {
1.18    ! djm       411:        int (*ec_init)(EC_KEY *key);
        !           412:        int (*ec_copy)(EC_KEY *dest, const EC_KEY *src);
        !           413:        int (*ec_set_group)(EC_KEY *key, const EC_GROUP *grp);
        !           414:        int (*ec_set_private)(EC_KEY *key, const BIGNUM *priv_key);
        !           415:        int (*ec_set_public)(EC_KEY *key, const EC_POINT *pub_key);
        !           416:        int (*ec_sign)(int, const unsigned char *, int, unsigned char *,
        !           417:            unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
        !           418:        RSA_METHOD *rsa_meth;
        !           419:        EC_KEY_METHOD *ec_meth;
1.12      djm       420:
1.18    ! djm       421:        if ((ec_meth = EC_KEY_METHOD_new(EC_KEY_OpenSSL())) == NULL)
        !           422:                return -1;
        !           423:        EC_KEY_METHOD_get_sign(ec_meth, &ec_sign, NULL, NULL);
        !           424:        EC_KEY_METHOD_set_sign(ec_meth, ec_sign, NULL, ecdsa_do_sign);
        !           425:        EC_KEY_METHOD_get_init(ec_meth, &ec_init, &helper->ec_finish,
        !           426:            &ec_copy, &ec_set_group, &ec_set_private, &ec_set_public);
        !           427:        EC_KEY_METHOD_set_init(ec_meth, ec_init, ecdsa_do_finish,
        !           428:            ec_copy, ec_set_group, ec_set_private, ec_set_public);
1.1       markus    429:
1.18    ! djm       430:        if ((rsa_meth = RSA_meth_dup(RSA_get_default_method())) == NULL)
1.17      djm       431:                fatal_f("RSA_meth_dup failed");
1.18    ! djm       432:        helper->rsa_finish = RSA_meth_get_finish(rsa_meth);
        !           433:        if (!RSA_meth_set1_name(rsa_meth, "ssh-pkcs11-helper") ||
        !           434:            !RSA_meth_set_priv_enc(rsa_meth, rsa_encrypt) ||
        !           435:            !RSA_meth_set_finish(rsa_meth, rsa_finish))
1.17      djm       436:                fatal_f("failed to prepare method");
1.12      djm       437:
1.18    ! djm       438:        helper->ec_meth = ec_meth;
        !           439:        helper->rsa_meth = rsa_meth;
        !           440:        return 0;
1.1       markus    441: }
                    442:
1.18    ! djm       443: static struct helper *
        !           444: pkcs11_start_helper(const char *path)
1.1       markus    445: {
                    446:        int pair[2];
1.18    ! djm       447:        char *prog, *verbosity = NULL;
        !           448:        struct helper *helper;
        !           449:        pid_t pid;
        !           450:
        !           451:        if (nhelpers >= INT_MAX)
        !           452:                fatal_f("too many helpers");
        !           453:        debug3_f("start helper for %s", path);
        !           454:        if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
        !           455:                error_f("socketpair: %s", strerror(errno));
        !           456:                return NULL;
1.12      djm       457:        }
1.18    ! djm       458:        helper = xcalloc(1, sizeof(*helper));
        !           459:        if (pkcs11_start_helper_methods(helper) == -1) {
        !           460:                error_f("pkcs11_start_helper_methods failed");
        !           461:                goto fail;
1.1       markus    462:        }
                    463:        if ((pid = fork()) == -1) {
1.18    ! djm       464:                error_f("fork: %s", strerror(errno));
        !           465:  fail:
        !           466:                close(pair[0]);
        !           467:                close(pair[1]);
        !           468:                RSA_meth_free(helper->rsa_meth);
        !           469:                EC_KEY_METHOD_free(helper->ec_meth);
        !           470:                free(helper);
        !           471:                return NULL;
1.1       markus    472:        } else if (pid == 0) {
                    473:                if ((dup2(pair[1], STDIN_FILENO) == -1) ||
                    474:                    (dup2(pair[1], STDOUT_FILENO) == -1)) {
                    475:                        fprintf(stderr, "dup2: %s\n", strerror(errno));
                    476:                        _exit(1);
                    477:                }
                    478:                close(pair[0]);
                    479:                close(pair[1]);
1.18    ! djm       480:                prog = getenv("SSH_PKCS11_HELPER");
        !           481:                if (prog == NULL || strlen(prog) == 0)
        !           482:                        prog = _PATH_SSH_PKCS11_HELPER;
        !           483:                if (log_level_get() >= SYSLOG_LEVEL_DEBUG1)
        !           484:                        verbosity = "-vvv";
        !           485:                debug_f("starting %s %s", prog,
1.15      djm       486:                    verbosity == NULL ? "" : verbosity);
1.18    ! djm       487:                execlp(prog, prog, verbosity, (char *)NULL);
        !           488:                fprintf(stderr, "exec: %s: %s\n", prog, strerror(errno));
1.1       markus    489:                _exit(1);
                    490:        }
                    491:        close(pair[1]);
1.18    ! djm       492:        helper->fd = pair[0];
        !           493:        helper->path = xstrdup(path);
        !           494:        helper->pid = pid;
        !           495:        debug3_f("helper %zu for \"%s\" on fd %d pid %ld", nhelpers,
        !           496:            helper->path, helper->fd, (long)helper->pid);
        !           497:        helpers = xrecallocarray(helpers, nhelpers,
        !           498:            nhelpers + 1, sizeof(*helpers));
        !           499:        helpers[nhelpers++] = helper;
        !           500:        return helper;
1.1       markus    501: }
                    502:
                    503: int
1.16      djm       504: pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp,
                    505:     char ***labelsp)
1.1       markus    506: {
1.7       markus    507:        struct sshkey *k;
1.12      djm       508:        int r, type;
1.1       markus    509:        u_char *blob;
1.16      djm       510:        char *label;
1.9       markus    511:        size_t blen;
                    512:        u_int nkeys, i;
                    513:        struct sshbuf *msg;
1.18    ! djm       514:        struct helper *helper;
1.1       markus    515:
1.18    ! djm       516:        if ((helper = helper_by_provider(name)) == NULL &&
        !           517:            (helper = pkcs11_start_helper(name)) == NULL)
        !           518:                return -1;
1.1       markus    519:
1.9       markus    520:        if ((msg = sshbuf_new()) == NULL)
1.17      djm       521:                fatal_f("sshbuf_new failed");
1.9       markus    522:        if ((r = sshbuf_put_u8(msg, SSH_AGENTC_ADD_SMARTCARD_KEY)) != 0 ||
                    523:            (r = sshbuf_put_cstring(msg, name)) != 0 ||
                    524:            (r = sshbuf_put_cstring(msg, pin)) != 0)
1.17      djm       525:                fatal_fr(r, "compose");
1.18    ! djm       526:        send_msg(helper->fd, msg);
1.9       markus    527:        sshbuf_reset(msg);
                    528:
1.18    ! djm       529:        type = recv_msg(helper->fd, msg);
1.12      djm       530:        if (type == SSH2_AGENT_IDENTITIES_ANSWER) {
1.9       markus    531:                if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
1.17      djm       532:                        fatal_fr(r, "parse nkeys");
1.9       markus    533:                *keysp = xcalloc(nkeys, sizeof(struct sshkey *));
1.16      djm       534:                if (labelsp)
                    535:                        *labelsp = xcalloc(nkeys, sizeof(char *));
1.1       markus    536:                for (i = 0; i < nkeys; i++) {
1.9       markus    537:                        /* XXX clean up properly instead of fatal() */
                    538:                        if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
1.16      djm       539:                            (r = sshbuf_get_cstring(msg, &label, NULL)) != 0)
1.17      djm       540:                                fatal_fr(r, "parse key");
1.9       markus    541:                        if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
1.17      djm       542:                                fatal_fr(r, "decode key");
1.18    ! djm       543:                        wrap_key(helper, k);
1.1       markus    544:                        (*keysp)[i] = k;
1.16      djm       545:                        if (labelsp)
                    546:                                (*labelsp)[i] = label;
                    547:                        else
                    548:                                free(label);
1.4       djm       549:                        free(blob);
1.1       markus    550:                }
1.12      djm       551:        } else if (type == SSH2_AGENT_FAILURE) {
                    552:                if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
                    553:                        nkeys = -1;
1.1       markus    554:        } else {
                    555:                nkeys = -1;
                    556:        }
1.9       markus    557:        sshbuf_free(msg);
1.1       markus    558:        return (nkeys);
                    559: }
                    560:
                    561: int
                    562: pkcs11_del_provider(char *name)
                    563: {
1.18    ! djm       564:        struct helper *helper;
1.1       markus    565:
1.18    ! djm       566:        /*
        !           567:         * ssh-agent deletes keys before calling this, so the helper entry
        !           568:         * should be gone before we get here.
        !           569:         */
        !           570:        debug3_f("delete %s", name);
        !           571:        if ((helper = helper_by_provider(name)) != NULL)
        !           572:                helper_terminate(helper);
        !           573:        return 0;
1.1       markus    574: }