Annotation of src/usr.bin/ssh/ssh-pkcs11-client.c, Revision 1.12
1.12 ! djm 1: /* $OpenBSD: ssh-pkcs11-client.c,v 1.11 2018/09/13 02:08:33 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.5 djm 27:
1.12 ! djm 28: #include <openssl/ecdsa.h>
1.5 djm 29: #include <openssl/rsa.h>
1.1 markus 30:
31: #include "pathnames.h"
32: #include "xmalloc.h"
1.9 markus 33: #include "sshbuf.h"
1.1 markus 34: #include "log.h"
35: #include "misc.h"
1.9 markus 36: #include "sshkey.h"
1.1 markus 37: #include "authfd.h"
38: #include "atomicio.h"
39: #include "ssh-pkcs11.h"
1.9 markus 40: #include "ssherr.h"
1.1 markus 41:
42: /* borrows code from sftp-server and ssh-agent */
43:
44: int fd = -1;
45: pid_t pid = -1;
46:
47: static void
1.9 markus 48: send_msg(struct sshbuf *m)
1.1 markus 49: {
50: u_char buf[4];
1.9 markus 51: size_t mlen = sshbuf_len(m);
52: int r;
1.1 markus 53:
1.9 markus 54: POKE_U32(buf, mlen);
1.1 markus 55: if (atomicio(vwrite, fd, buf, 4) != 4 ||
1.10 markus 56: atomicio(vwrite, fd, sshbuf_mutable_ptr(m),
1.9 markus 57: sshbuf_len(m)) != sshbuf_len(m))
1.1 markus 58: error("write to helper failed");
1.9 markus 59: if ((r = sshbuf_consume(m, mlen)) != 0)
60: fatal("%s: buffer error: %s", __func__, ssh_err(r));
1.1 markus 61: }
62:
63: static int
1.9 markus 64: recv_msg(struct sshbuf *m)
1.1 markus 65: {
66: u_int l, len;
1.9 markus 67: u_char c, buf[1024];
68: int r;
1.1 markus 69:
70: if ((len = atomicio(read, fd, buf, 4)) != 4) {
71: error("read from helper failed: %u", len);
72: return (0); /* XXX */
73: }
1.9 markus 74: len = PEEK_U32(buf);
1.1 markus 75: if (len > 256 * 1024)
76: fatal("response too long: %u", len);
77: /* read len bytes into m */
1.9 markus 78: sshbuf_reset(m);
1.1 markus 79: while (len > 0) {
80: l = len;
81: if (l > sizeof(buf))
82: l = sizeof(buf);
83: if (atomicio(read, fd, buf, l) != l) {
84: error("response from helper failed.");
85: return (0); /* XXX */
86: }
1.9 markus 87: if ((r = sshbuf_put(m, buf, l)) != 0)
88: fatal("%s: buffer error: %s", __func__, ssh_err(r));
1.1 markus 89: len -= l;
90: }
1.9 markus 91: if ((r = sshbuf_get_u8(m, &c)) != 0)
92: fatal("%s: buffer error: %s", __func__, ssh_err(r));
93: return c;
1.1 markus 94: }
95:
96: int
97: pkcs11_init(int interactive)
98: {
99: return (0);
100: }
101:
102: void
103: pkcs11_terminate(void)
104: {
1.8 tb 105: if (fd >= 0)
106: close(fd);
1.1 markus 107: }
108:
109: static int
1.12 ! djm 110: rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
1.1 markus 111: {
1.7 markus 112: struct sshkey key; /* XXX */
1.1 markus 113: u_char *blob, *signature = NULL;
1.9 markus 114: size_t blen, slen = 0;
115: int r, ret = -1;
116: struct sshbuf *msg;
1.1 markus 117:
118: if (padding != RSA_PKCS1_PADDING)
119: return (-1);
120: key.type = KEY_RSA;
121: key.rsa = rsa;
1.9 markus 122: if ((r = sshkey_to_blob(&key, &blob, &blen)) != 0) {
123: error("%s: sshkey_to_blob: %s", __func__, ssh_err(r));
1.1 markus 124: return -1;
1.9 markus 125: }
126: if ((msg = sshbuf_new()) == NULL)
127: fatal("%s: sshbuf_new failed", __func__);
128: if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
129: (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
130: (r = sshbuf_put_string(msg, from, flen)) != 0 ||
131: (r = sshbuf_put_u32(msg, 0)) != 0)
132: fatal("%s: buffer error: %s", __func__, ssh_err(r));
1.4 djm 133: free(blob);
1.9 markus 134: send_msg(msg);
135: sshbuf_reset(msg);
1.1 markus 136:
1.9 markus 137: if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) {
138: if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
139: fatal("%s: buffer error: %s", __func__, ssh_err(r));
140: if (slen <= (size_t)RSA_size(rsa)) {
1.1 markus 141: memcpy(to, signature, slen);
142: ret = slen;
143: }
1.4 djm 144: free(signature);
1.1 markus 145: }
1.9 markus 146: sshbuf_free(msg);
1.1 markus 147: return (ret);
148: }
149:
1.12 ! djm 150: static ECDSA_SIG *
! 151: ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
! 152: const BIGNUM *rp, EC_KEY *ec)
! 153: {
! 154: struct sshkey key; /* XXX */
! 155: u_char *blob, *signature = NULL;
! 156: const u_char *cp;
! 157: size_t blen, slen = 0;
! 158: ECDSA_SIG *ret = NULL;
! 159: struct sshbuf *msg;
! 160: int r;
! 161:
! 162: key.type = KEY_ECDSA;
! 163: key.ecdsa = ec;
! 164: key.ecdsa_nid = sshkey_ecdsa_key_to_nid(ec);
! 165: if (key.ecdsa_nid < 0) {
! 166: error("%s: couldn't get curve nid", __func__);
! 167: return (NULL);
! 168: }
! 169: if ((r = sshkey_to_blob(&key, &blob, &blen)) != 0) {
! 170: error("%s: sshkey_to_blob: %s", __func__, ssh_err(r));
! 171: return (NULL);
! 172: }
! 173: if ((msg = sshbuf_new()) == NULL)
! 174: fatal("%s: sshbuf_new failed", __func__);
! 175: if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
! 176: (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
! 177: (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 ||
! 178: (r = sshbuf_put_u32(msg, 0)) != 0)
! 179: fatal("%s: buffer error: %s", __func__, ssh_err(r));
! 180: free(blob);
! 181: send_msg(msg);
! 182: sshbuf_reset(msg);
! 183:
! 184: if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) {
! 185: if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
! 186: fatal("%s: buffer error: %s", __func__, ssh_err(r));
! 187: cp = signature;
! 188: ret = d2i_ECDSA_SIG(NULL, &cp, slen);
! 189: free(signature);
! 190: }
! 191:
! 192: sshbuf_free(msg);
! 193: return (ret);
! 194: }
! 195:
! 196: static RSA_METHOD *helper_rsa;
! 197: static EC_KEY_METHOD *helper_ecdsa;
! 198:
! 199: /* redirect private key crypto operations to the ssh-pkcs11-helper */
! 200: static void
! 201: wrap_key(struct sshkey *k)
! 202: {
! 203: if (k->type == KEY_RSA)
! 204: RSA_set_method(k->rsa, helper_rsa);
! 205: else if (k->type == KEY_ECDSA)
! 206: EC_KEY_set_method(k->ecdsa, helper_ecdsa);
! 207: else
! 208: fatal("%s: unknown key type", __func__);
! 209: }
! 210:
1.1 markus 211: static int
1.12 ! djm 212: pkcs11_start_helper_methods(void)
1.1 markus 213: {
1.12 ! djm 214: if (helper_ecdsa != NULL)
! 215: return (0);
! 216:
! 217: int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
! 218: unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
! 219: if (helper_ecdsa != NULL)
! 220: return (0);
! 221: helper_ecdsa = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
! 222: if (helper_ecdsa == NULL)
! 223: return (-1);
! 224: EC_KEY_METHOD_get_sign(helper_ecdsa, &orig_sign, NULL, NULL);
! 225: EC_KEY_METHOD_set_sign(helper_ecdsa, orig_sign, NULL, ecdsa_do_sign);
1.1 markus 226:
1.11 djm 227: if ((helper_rsa = RSA_meth_dup(RSA_get_default_method())) == NULL)
228: fatal("%s: RSA_meth_dup failed", __func__);
229: if (!RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper") ||
1.12 ! djm 230: !RSA_meth_set_priv_enc(helper_rsa, rsa_encrypt))
1.11 djm 231: fatal("%s: failed to prepare method", __func__);
1.12 ! djm 232:
1.1 markus 233: return (0);
234: }
235:
236: static int
237: pkcs11_start_helper(void)
238: {
239: int pair[2];
240:
1.12 ! djm 241: if (pkcs11_start_helper_methods() == -1) {
! 242: error("pkcs11_start_helper_methods failed");
! 243: return (-1);
! 244: }
! 245:
1.1 markus 246: if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
247: error("socketpair: %s", strerror(errno));
248: return (-1);
249: }
250: if ((pid = fork()) == -1) {
251: error("fork: %s", strerror(errno));
252: return (-1);
253: } else if (pid == 0) {
254: if ((dup2(pair[1], STDIN_FILENO) == -1) ||
255: (dup2(pair[1], STDOUT_FILENO) == -1)) {
256: fprintf(stderr, "dup2: %s\n", strerror(errno));
257: _exit(1);
258: }
259: close(pair[0]);
260: close(pair[1]);
261: execlp(_PATH_SSH_PKCS11_HELPER, _PATH_SSH_PKCS11_HELPER,
1.6 mmcc 262: (char *)NULL);
1.1 markus 263: fprintf(stderr, "exec: %s: %s\n", _PATH_SSH_PKCS11_HELPER,
264: strerror(errno));
265: _exit(1);
266: }
267: close(pair[1]);
268: fd = pair[0];
269: return (0);
270: }
271:
272: int
1.9 markus 273: pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp)
1.1 markus 274: {
1.7 markus 275: struct sshkey *k;
1.12 ! djm 276: int r, type;
1.1 markus 277: u_char *blob;
1.9 markus 278: size_t blen;
279: u_int nkeys, i;
280: struct sshbuf *msg;
1.1 markus 281:
282: if (fd < 0 && pkcs11_start_helper() < 0)
283: return (-1);
284:
1.9 markus 285: if ((msg = sshbuf_new()) == NULL)
286: fatal("%s: sshbuf_new failed", __func__);
287: if ((r = sshbuf_put_u8(msg, SSH_AGENTC_ADD_SMARTCARD_KEY)) != 0 ||
288: (r = sshbuf_put_cstring(msg, name)) != 0 ||
289: (r = sshbuf_put_cstring(msg, pin)) != 0)
290: fatal("%s: buffer error: %s", __func__, ssh_err(r));
291: send_msg(msg);
292: sshbuf_reset(msg);
293:
1.12 ! djm 294: type = recv_msg(msg);
! 295: if (type == SSH2_AGENT_IDENTITIES_ANSWER) {
1.9 markus 296: if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
297: fatal("%s: buffer error: %s", __func__, ssh_err(r));
298: *keysp = xcalloc(nkeys, sizeof(struct sshkey *));
1.1 markus 299: for (i = 0; i < nkeys; i++) {
1.9 markus 300: /* XXX clean up properly instead of fatal() */
301: if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
302: (r = sshbuf_skip_string(msg)) != 0)
303: fatal("%s: buffer error: %s",
304: __func__, ssh_err(r));
305: if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
306: fatal("%s: bad key: %s", __func__, ssh_err(r));
1.12 ! djm 307: wrap_key(k);
1.1 markus 308: (*keysp)[i] = k;
1.4 djm 309: free(blob);
1.1 markus 310: }
1.12 ! djm 311: } else if (type == SSH2_AGENT_FAILURE) {
! 312: if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
! 313: nkeys = -1;
1.1 markus 314: } else {
315: nkeys = -1;
316: }
1.9 markus 317: sshbuf_free(msg);
1.1 markus 318: return (nkeys);
319: }
320:
321: int
322: pkcs11_del_provider(char *name)
323: {
1.9 markus 324: int r, ret = -1;
325: struct sshbuf *msg;
1.1 markus 326:
1.9 markus 327: if ((msg = sshbuf_new()) == NULL)
328: fatal("%s: sshbuf_new failed", __func__);
329: if ((r = sshbuf_put_u8(msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY)) != 0 ||
330: (r = sshbuf_put_cstring(msg, name)) != 0 ||
331: (r = sshbuf_put_cstring(msg, "")) != 0)
332: fatal("%s: buffer error: %s", __func__, ssh_err(r));
333: send_msg(msg);
334: sshbuf_reset(msg);
1.1 markus 335:
1.9 markus 336: if (recv_msg(msg) == SSH_AGENT_SUCCESS)
1.1 markus 337: ret = 0;
1.9 markus 338: sshbuf_free(msg);
1.1 markus 339: return (ret);
340: }