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

1.1     ! markus      1: /*
        !             2:  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
        !             3:  *
        !             4:  * Permission to use, copy, modify, and distribute this software for any
        !             5:  * purpose with or without fee is hereby granted, provided that the above
        !             6:  * copyright notice and this permission notice appear in all copies.
        !             7:  *
        !             8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !             9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            15:  */
        !            16:
        !            17: #include <sys/types.h>
        !            18: #include <sys/time.h>
        !            19: #include <sys/socket.h>
        !            20:
        !            21: #include <stdarg.h>
        !            22: #include <string.h>
        !            23: #include <unistd.h>
        !            24: #include <errno.h>
        !            25:
        !            26: #include "pathnames.h"
        !            27: #include "xmalloc.h"
        !            28: #include "buffer.h"
        !            29: #include "log.h"
        !            30: #include "misc.h"
        !            31: #include "key.h"
        !            32: #include "authfd.h"
        !            33: #include "atomicio.h"
        !            34: #include "ssh-pkcs11.h"
        !            35:
        !            36: /* borrows code from sftp-server and ssh-agent */
        !            37:
        !            38: int fd = -1;
        !            39: pid_t pid = -1;
        !            40:
        !            41: static void
        !            42: send_msg(Buffer *m)
        !            43: {
        !            44:        u_char buf[4];
        !            45:        int mlen = buffer_len(m);
        !            46:
        !            47:        put_u32(buf, mlen);
        !            48:        if (atomicio(vwrite, fd, buf, 4) != 4 ||
        !            49:            atomicio(vwrite, fd, buffer_ptr(m),
        !            50:            buffer_len(m)) != buffer_len(m))
        !            51:                error("write to helper failed");
        !            52:        buffer_consume(m, mlen);
        !            53: }
        !            54:
        !            55: static int
        !            56: recv_msg(Buffer *m)
        !            57: {
        !            58:        u_int l, len;
        !            59:        u_char buf[1024];
        !            60:
        !            61:        if ((len = atomicio(read, fd, buf, 4)) != 4) {
        !            62:                error("read from helper failed: %u", len);
        !            63:                return (0); /* XXX */
        !            64:        }
        !            65:        len = get_u32(buf);
        !            66:        if (len > 256 * 1024)
        !            67:                fatal("response too long: %u", len);
        !            68:        /* read len bytes into m */
        !            69:        buffer_clear(m);
        !            70:        while (len > 0) {
        !            71:                l = len;
        !            72:                if (l > sizeof(buf))
        !            73:                        l = sizeof(buf);
        !            74:                if (atomicio(read, fd, buf, l) != l) {
        !            75:                        error("response from helper failed.");
        !            76:                        return (0); /* XXX */
        !            77:                }
        !            78:                buffer_append(m, buf, l);
        !            79:                len -= l;
        !            80:        }
        !            81:        return (buffer_get_char(m));
        !            82: }
        !            83:
        !            84: int
        !            85: pkcs11_init(int interactive)
        !            86: {
        !            87:        return (0);
        !            88: }
        !            89:
        !            90: void
        !            91: pkcs11_terminate(void)
        !            92: {
        !            93:        close(fd);
        !            94: }
        !            95:
        !            96: static int
        !            97: pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
        !            98:     int padding)
        !            99: {
        !           100:        Key key;
        !           101:        u_char *blob, *signature = NULL;
        !           102:        u_int blen, slen = 0;
        !           103:        int ret = -1;
        !           104:        Buffer msg;
        !           105:
        !           106:        if (padding != RSA_PKCS1_PADDING)
        !           107:                return (-1);
        !           108:        key.type = KEY_RSA;
        !           109:        key.rsa = rsa;
        !           110:        if (key_to_blob(&key, &blob, &blen) == 0)
        !           111:                return -1;
        !           112:        buffer_init(&msg);
        !           113:        buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST);
        !           114:        buffer_put_string(&msg, blob, blen);
        !           115:        buffer_put_string(&msg, from, flen);
        !           116:        buffer_put_int(&msg, 0);
        !           117:        xfree(blob);
        !           118:        send_msg(&msg);
        !           119:
        !           120:        if (recv_msg(&msg) == SSH2_AGENT_SIGN_RESPONSE) {
        !           121:                signature = buffer_get_string(&msg, &slen);
        !           122:                if (slen <= (u_int)RSA_size(rsa)) {
        !           123:                        memcpy(to, signature, slen);
        !           124:                        ret = slen;
        !           125:                }
        !           126:                xfree(signature);
        !           127:        }
        !           128:        return (ret);
        !           129: }
        !           130:
        !           131: /* redirect the private key encrypt operation to the ssh-pkcs11-helper */
        !           132: static int
        !           133: wrap_key(RSA *rsa)
        !           134: {
        !           135:        static RSA_METHOD helper_rsa;
        !           136:
        !           137:        memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa));
        !           138:        helper_rsa.name = "ssh-pkcs11-helper";
        !           139:        helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt;
        !           140:        RSA_set_method(rsa, &helper_rsa);
        !           141:        return (0);
        !           142: }
        !           143:
        !           144: static int
        !           145: pkcs11_start_helper(void)
        !           146: {
        !           147:        int pair[2];
        !           148:
        !           149:        if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
        !           150:                error("socketpair: %s", strerror(errno));
        !           151:                return (-1);
        !           152:        }
        !           153:        if ((pid = fork()) == -1) {
        !           154:                error("fork: %s", strerror(errno));
        !           155:                return (-1);
        !           156:        } else if (pid == 0) {
        !           157:                if ((dup2(pair[1], STDIN_FILENO) == -1) ||
        !           158:                    (dup2(pair[1], STDOUT_FILENO) == -1)) {
        !           159:                        fprintf(stderr, "dup2: %s\n", strerror(errno));
        !           160:                        _exit(1);
        !           161:                }
        !           162:                close(pair[0]);
        !           163:                close(pair[1]);
        !           164:                execlp(_PATH_SSH_PKCS11_HELPER, _PATH_SSH_PKCS11_HELPER,
        !           165:                    (char *) 0);
        !           166:                fprintf(stderr, "exec: %s: %s\n", _PATH_SSH_PKCS11_HELPER,
        !           167:                    strerror(errno));
        !           168:                _exit(1);
        !           169:        }
        !           170:        close(pair[1]);
        !           171:        fd = pair[0];
        !           172:        return (0);
        !           173: }
        !           174:
        !           175: int
        !           176: pkcs11_add_provider(char *name, char *pin, Key ***keysp)
        !           177: {
        !           178:        Key *k;
        !           179:        int i, nkeys;
        !           180:        u_char *blob;
        !           181:        u_int blen;
        !           182:        Buffer msg;
        !           183:
        !           184:        if (fd < 0 && pkcs11_start_helper() < 0)
        !           185:                return (-1);
        !           186:
        !           187:        buffer_init(&msg);
        !           188:        buffer_put_char(&msg, SSH_AGENTC_ADD_SMARTCARD_KEY);
        !           189:        buffer_put_cstring(&msg, name);
        !           190:        buffer_put_cstring(&msg, pin);
        !           191:        send_msg(&msg);
        !           192:        buffer_clear(&msg);
        !           193:
        !           194:        if (recv_msg(&msg) == SSH2_AGENT_IDENTITIES_ANSWER) {
        !           195:                nkeys = buffer_get_int(&msg);
        !           196:                *keysp = xcalloc(nkeys, sizeof(Key *));
        !           197:                for (i = 0; i < nkeys; i++) {
        !           198:                        blob = buffer_get_string(&msg, &blen);
        !           199:                        xfree(buffer_get_string(&msg, NULL));
        !           200:                        k = key_from_blob(blob, blen);
        !           201:                        wrap_key(k->rsa);
        !           202:                        (*keysp)[i] = k;
        !           203:                        xfree(blob);
        !           204:                }
        !           205:        } else {
        !           206:                nkeys = -1;
        !           207:        }
        !           208:        buffer_free(&msg);
        !           209:        return (nkeys);
        !           210: }
        !           211:
        !           212: int
        !           213: pkcs11_del_provider(char *name)
        !           214: {
        !           215:        int ret = -1;
        !           216:        Buffer msg;
        !           217:
        !           218:        buffer_init(&msg);
        !           219:        buffer_put_char(&msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY);
        !           220:        buffer_put_cstring(&msg, name);
        !           221:        buffer_put_cstring(&msg, "");
        !           222:        send_msg(&msg);
        !           223:        buffer_clear(&msg);
        !           224:
        !           225:        if (recv_msg(&msg) == SSH_AGENT_SUCCESS)
        !           226:                ret = 0;
        !           227:        buffer_free(&msg);
        !           228:        return (ret);
        !           229: }