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: }