[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.9

1.9     ! markus      1: /* $OpenBSD: ssh-pkcs11-client.c,v 1.8 2018/02/05 05:37:46 tb 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/time.h>
                     20: #include <sys/socket.h>
                     21:
                     22: #include <stdarg.h>
                     23: #include <string.h>
                     24: #include <unistd.h>
                     25: #include <errno.h>
1.5       djm        26:
                     27: #include <openssl/rsa.h>
1.1       markus     28:
                     29: #include "pathnames.h"
                     30: #include "xmalloc.h"
1.9     ! markus     31: #include "sshbuf.h"
1.1       markus     32: #include "log.h"
                     33: #include "misc.h"
1.9     ! markus     34: #include "sshkey.h"
1.1       markus     35: #include "authfd.h"
                     36: #include "atomicio.h"
                     37: #include "ssh-pkcs11.h"
1.9     ! markus     38: #include "ssherr.h"
1.1       markus     39:
                     40: /* borrows code from sftp-server and ssh-agent */
                     41:
                     42: int fd = -1;
                     43: pid_t pid = -1;
                     44:
                     45: static void
1.9     ! markus     46: send_msg(struct sshbuf *m)
1.1       markus     47: {
                     48:        u_char buf[4];
1.9     ! markus     49:        size_t mlen = sshbuf_len(m);
        !            50:        int r;
1.1       markus     51:
1.9     ! markus     52:        POKE_U32(buf, mlen);
1.1       markus     53:        if (atomicio(vwrite, fd, buf, 4) != 4 ||
1.9     ! markus     54:            atomicio(vwrite, fd, (u_char *)sshbuf_ptr(m),
        !            55:            sshbuf_len(m)) != sshbuf_len(m))
1.1       markus     56:                error("write to helper failed");
1.9     ! markus     57:        if ((r = sshbuf_consume(m, mlen)) != 0)
        !            58:                fatal("%s: buffer error: %s", __func__, ssh_err(r));
1.1       markus     59: }
                     60:
                     61: static int
1.9     ! markus     62: recv_msg(struct sshbuf *m)
1.1       markus     63: {
                     64:        u_int l, len;
1.9     ! markus     65:        u_char c, buf[1024];
        !            66:        int r;
1.1       markus     67:
                     68:        if ((len = atomicio(read, fd, buf, 4)) != 4) {
                     69:                error("read from helper failed: %u", len);
                     70:                return (0); /* XXX */
                     71:        }
1.9     ! markus     72:        len = PEEK_U32(buf);
1.1       markus     73:        if (len > 256 * 1024)
                     74:                fatal("response too long: %u", len);
                     75:        /* read len bytes into m */
1.9     ! markus     76:        sshbuf_reset(m);
1.1       markus     77:        while (len > 0) {
                     78:                l = len;
                     79:                if (l > sizeof(buf))
                     80:                        l = sizeof(buf);
                     81:                if (atomicio(read, fd, buf, l) != l) {
                     82:                        error("response from helper failed.");
                     83:                        return (0); /* XXX */
                     84:                }
1.9     ! markus     85:                if ((r = sshbuf_put(m, buf, l)) != 0)
        !            86:                        fatal("%s: buffer error: %s", __func__, ssh_err(r));
1.1       markus     87:                len -= l;
                     88:        }
1.9     ! markus     89:        if ((r = sshbuf_get_u8(m, &c)) != 0)
        !            90:                fatal("%s: buffer error: %s", __func__, ssh_err(r));
        !            91:        return c;
1.1       markus     92: }
                     93:
                     94: int
                     95: pkcs11_init(int interactive)
                     96: {
                     97:        return (0);
                     98: }
                     99:
                    100: void
                    101: pkcs11_terminate(void)
                    102: {
1.8       tb        103:        if (fd >= 0)
                    104:                close(fd);
1.1       markus    105: }
                    106:
                    107: static int
                    108: pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
                    109:     int padding)
                    110: {
1.7       markus    111:        struct sshkey key;      /* XXX */
1.1       markus    112:        u_char *blob, *signature = NULL;
1.9     ! markus    113:        size_t blen, slen = 0;
        !           114:        int r, ret = -1;
        !           115:        struct sshbuf *msg;
1.1       markus    116:
                    117:        if (padding != RSA_PKCS1_PADDING)
                    118:                return (-1);
                    119:        key.type = KEY_RSA;
                    120:        key.rsa = rsa;
1.9     ! markus    121:        if ((r = sshkey_to_blob(&key, &blob, &blen)) != 0) {
        !           122:                error("%s: sshkey_to_blob: %s", __func__, ssh_err(r));
1.1       markus    123:                return -1;
1.9     ! markus    124:        }
        !           125:        if ((msg = sshbuf_new()) == NULL)
        !           126:                fatal("%s: sshbuf_new failed", __func__);
        !           127:        if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
        !           128:            (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
        !           129:            (r = sshbuf_put_string(msg, from, flen)) != 0 ||
        !           130:            (r = sshbuf_put_u32(msg, 0)) != 0)
        !           131:                fatal("%s: buffer error: %s", __func__, ssh_err(r));
1.4       djm       132:        free(blob);
1.9     ! markus    133:        send_msg(msg);
        !           134:        sshbuf_reset(msg);
1.1       markus    135:
1.9     ! markus    136:        if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) {
        !           137:                if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
        !           138:                        fatal("%s: buffer error: %s", __func__, ssh_err(r));
        !           139:                if (slen <= (size_t)RSA_size(rsa)) {
1.1       markus    140:                        memcpy(to, signature, slen);
                    141:                        ret = slen;
                    142:                }
1.4       djm       143:                free(signature);
1.1       markus    144:        }
1.9     ! markus    145:        sshbuf_free(msg);
1.1       markus    146:        return (ret);
                    147: }
                    148:
                    149: /* redirect the private key encrypt operation to the ssh-pkcs11-helper */
                    150: static int
                    151: wrap_key(RSA *rsa)
                    152: {
                    153:        static RSA_METHOD helper_rsa;
                    154:
                    155:        memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa));
                    156:        helper_rsa.name = "ssh-pkcs11-helper";
                    157:        helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt;
                    158:        RSA_set_method(rsa, &helper_rsa);
                    159:        return (0);
                    160: }
                    161:
                    162: static int
                    163: pkcs11_start_helper(void)
                    164: {
                    165:        int pair[2];
                    166:
                    167:        if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
                    168:                error("socketpair: %s", strerror(errno));
                    169:                return (-1);
                    170:        }
                    171:        if ((pid = fork()) == -1) {
                    172:                error("fork: %s", strerror(errno));
                    173:                return (-1);
                    174:        } else if (pid == 0) {
                    175:                if ((dup2(pair[1], STDIN_FILENO) == -1) ||
                    176:                    (dup2(pair[1], STDOUT_FILENO) == -1)) {
                    177:                        fprintf(stderr, "dup2: %s\n", strerror(errno));
                    178:                        _exit(1);
                    179:                }
                    180:                close(pair[0]);
                    181:                close(pair[1]);
                    182:                execlp(_PATH_SSH_PKCS11_HELPER, _PATH_SSH_PKCS11_HELPER,
1.6       mmcc      183:                    (char *)NULL);
1.1       markus    184:                fprintf(stderr, "exec: %s: %s\n", _PATH_SSH_PKCS11_HELPER,
                    185:                    strerror(errno));
                    186:                _exit(1);
                    187:        }
                    188:        close(pair[1]);
                    189:        fd = pair[0];
                    190:        return (0);
                    191: }
                    192:
                    193: int
1.9     ! markus    194: pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp)
1.1       markus    195: {
1.7       markus    196:        struct sshkey *k;
1.9     ! markus    197:        int r;
1.1       markus    198:        u_char *blob;
1.9     ! markus    199:        size_t blen;
        !           200:        u_int nkeys, i;
        !           201:        struct sshbuf *msg;
1.1       markus    202:
                    203:        if (fd < 0 && pkcs11_start_helper() < 0)
                    204:                return (-1);
                    205:
1.9     ! markus    206:        if ((msg = sshbuf_new()) == NULL)
        !           207:                fatal("%s: sshbuf_new failed", __func__);
        !           208:        if ((r = sshbuf_put_u8(msg, SSH_AGENTC_ADD_SMARTCARD_KEY)) != 0 ||
        !           209:            (r = sshbuf_put_cstring(msg, name)) != 0 ||
        !           210:            (r = sshbuf_put_cstring(msg, pin)) != 0)
        !           211:                fatal("%s: buffer error: %s", __func__, ssh_err(r));
        !           212:        send_msg(msg);
        !           213:        sshbuf_reset(msg);
        !           214:
        !           215:        if (recv_msg(msg) == SSH2_AGENT_IDENTITIES_ANSWER) {
        !           216:                if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
        !           217:                        fatal("%s: buffer error: %s", __func__, ssh_err(r));
        !           218:                *keysp = xcalloc(nkeys, sizeof(struct sshkey *));
1.1       markus    219:                for (i = 0; i < nkeys; i++) {
1.9     ! markus    220:                        /* XXX clean up properly instead of fatal() */
        !           221:                        if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
        !           222:                            (r = sshbuf_skip_string(msg)) != 0)
        !           223:                                fatal("%s: buffer error: %s",
        !           224:                                    __func__, ssh_err(r));
        !           225:                        if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
        !           226:                                fatal("%s: bad key: %s", __func__, ssh_err(r));
1.1       markus    227:                        wrap_key(k->rsa);
                    228:                        (*keysp)[i] = k;
1.4       djm       229:                        free(blob);
1.1       markus    230:                }
                    231:        } else {
                    232:                nkeys = -1;
                    233:        }
1.9     ! markus    234:        sshbuf_free(msg);
1.1       markus    235:        return (nkeys);
                    236: }
                    237:
                    238: int
                    239: pkcs11_del_provider(char *name)
                    240: {
1.9     ! markus    241:        int r, ret = -1;
        !           242:        struct sshbuf *msg;
1.1       markus    243:
1.9     ! markus    244:        if ((msg = sshbuf_new()) == NULL)
        !           245:                fatal("%s: sshbuf_new failed", __func__);
        !           246:        if ((r = sshbuf_put_u8(msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY)) != 0 ||
        !           247:            (r = sshbuf_put_cstring(msg, name)) != 0 ||
        !           248:            (r = sshbuf_put_cstring(msg, "")) != 0)
        !           249:                fatal("%s: buffer error: %s", __func__, ssh_err(r));
        !           250:        send_msg(msg);
        !           251:        sshbuf_reset(msg);
1.1       markus    252:
1.9     ! markus    253:        if (recv_msg(msg) == SSH_AGENT_SUCCESS)
1.1       markus    254:                ret = 0;
1.9     ! markus    255:        sshbuf_free(msg);
1.1       markus    256:        return (ret);
                    257: }