Annotation of src/crypto/external/bsd/openssh/dist/ssh-pkcs11-helper.c, Revision 1.10
1.9 christos 1: /* $NetBSD: ssh-pkcs11-helper.c,v 1.8 2015/04/03 23:58:19 christos Exp $ */
1.10 ! christos 2: /* $OpenBSD: ssh-pkcs11-helper.c,v 1.12 2016/02/15 09:47:49 dtucker Exp $ */
! 3:
1.1 adam 4: /*
5: * Copyright (c) 2010 Markus Friedl. All rights reserved.
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
1.2 adam 19: #include "includes.h"
1.9 christos 20: __RCSID("$NetBSD: ssh-pkcs11-helper.c,v 1.8 2015/04/03 23:58:19 christos Exp $");
1.1 adam 21:
1.8 christos 22: #include <sys/types.h>
1.1 adam 23: #include <sys/queue.h>
24: #include <sys/time.h>
1.2 adam 25: #include <sys/param.h>
1.1 adam 26:
27: #include <stdarg.h>
28: #include <string.h>
29: #include <unistd.h>
30: #include <errno.h>
31:
32: #include "xmalloc.h"
33: #include "buffer.h"
34: #include "log.h"
35: #include "misc.h"
36: #include "key.h"
37: #include "authfd.h"
38: #include "ssh-pkcs11.h"
39:
40: /* borrows code from sftp-server and ssh-agent */
41:
42: struct pkcs11_keyinfo {
43: Key *key;
44: char *providername;
45: TAILQ_ENTRY(pkcs11_keyinfo) next;
46: };
47:
48: TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist;
49:
50: #define MAX_MSG_LENGTH 10240 /*XXX*/
51:
52: /* helper */
53: #define get_int() buffer_get_int(&iqueue);
54: #define get_string(lenp) buffer_get_string(&iqueue, lenp);
55:
56: /* input and output queue */
57: Buffer iqueue;
58: Buffer oqueue;
59:
60: static void
61: add_key(Key *k, char *name)
62: {
63: struct pkcs11_keyinfo *ki;
64:
65: ki = xcalloc(1, sizeof(*ki));
66: ki->providername = xstrdup(name);
67: ki->key = k;
68: TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next);
69: }
70:
71: static void
72: del_keys_by_name(char *name)
73: {
74: struct pkcs11_keyinfo *ki, *nxt;
75:
76: for (ki = TAILQ_FIRST(&pkcs11_keylist); ki; ki = nxt) {
77: nxt = TAILQ_NEXT(ki, next);
78: if (!strcmp(ki->providername, name)) {
79: TAILQ_REMOVE(&pkcs11_keylist, ki, next);
1.5 christos 80: free(ki->providername);
1.1 adam 81: key_free(ki->key);
82: free(ki);
83: }
84: }
85: }
86:
87: /* lookup matching 'private' key */
88: static Key *
89: lookup_key(Key *k)
90: {
91: struct pkcs11_keyinfo *ki;
92:
93: TAILQ_FOREACH(ki, &pkcs11_keylist, next) {
94: debug("check %p %s", ki, ki->providername);
95: if (key_equal(k, ki->key))
96: return (ki->key);
97: }
98: return (NULL);
99: }
100:
101: static void
102: send_msg(Buffer *m)
103: {
104: int mlen = buffer_len(m);
105:
106: buffer_put_int(&oqueue, mlen);
107: buffer_append(&oqueue, buffer_ptr(m), mlen);
108: buffer_consume(m, mlen);
109: }
110:
111: static void
112: process_add(void)
113: {
114: char *name, *pin;
115: Key **keys;
116: int i, nkeys;
117: u_char *blob;
118: u_int blen;
119: Buffer msg;
120:
121: buffer_init(&msg);
122: name = get_string(NULL);
123: pin = get_string(NULL);
124: if ((nkeys = pkcs11_add_provider(name, pin, &keys)) > 0) {
125: buffer_put_char(&msg, SSH2_AGENT_IDENTITIES_ANSWER);
126: buffer_put_int(&msg, nkeys);
127: for (i = 0; i < nkeys; i++) {
1.6 christos 128: if (key_to_blob(keys[i], &blob, &blen) == 0)
129: continue;
1.1 adam 130: buffer_put_string(&msg, blob, blen);
131: buffer_put_cstring(&msg, name);
1.5 christos 132: free(blob);
1.1 adam 133: add_key(keys[i], name);
134: }
1.5 christos 135: free(keys);
1.1 adam 136: } else {
137: buffer_put_char(&msg, SSH_AGENT_FAILURE);
138: }
1.5 christos 139: free(pin);
140: free(name);
1.1 adam 141: send_msg(&msg);
142: buffer_free(&msg);
143: }
144:
145: static void
146: process_del(void)
147: {
148: char *name, *pin;
149: Buffer msg;
150:
151: buffer_init(&msg);
152: name = get_string(NULL);
153: pin = get_string(NULL);
154: del_keys_by_name(name);
155: if (pkcs11_del_provider(name) == 0)
156: buffer_put_char(&msg, SSH_AGENT_SUCCESS);
157: else
158: buffer_put_char(&msg, SSH_AGENT_FAILURE);
1.5 christos 159: free(pin);
160: free(name);
1.1 adam 161: send_msg(&msg);
162: buffer_free(&msg);
163: }
164:
165: static void
166: process_sign(void)
167: {
168: u_char *blob, *data, *signature = NULL;
169: u_int blen, dlen, slen = 0;
1.7 christos 170: int ok = -1;
1.1 adam 171: Key *key, *found;
172: Buffer msg;
173:
174: blob = get_string(&blen);
175: data = get_string(&dlen);
1.4 christos 176: (void)get_int(); /* XXX ignore flags */
1.1 adam 177:
178: if ((key = key_from_blob(blob, blen)) != NULL) {
179: if ((found = lookup_key(key)) != NULL) {
1.7 christos 180: #ifdef WITH_OPENSSL
181: int ret;
182:
1.1 adam 183: slen = RSA_size(key->rsa);
184: signature = xmalloc(slen);
185: if ((ret = RSA_private_encrypt(dlen, data, signature,
186: found->rsa, RSA_PKCS1_PADDING)) != -1) {
187: slen = ret;
188: ok = 0;
189: }
1.7 christos 190: #endif /* WITH_OPENSSL */
1.1 adam 191: }
192: key_free(key);
193: }
194: buffer_init(&msg);
195: if (ok == 0) {
196: buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE);
197: buffer_put_string(&msg, signature, slen);
198: } else {
199: buffer_put_char(&msg, SSH_AGENT_FAILURE);
200: }
1.5 christos 201: free(data);
202: free(blob);
203: free(signature);
1.1 adam 204: send_msg(&msg);
205: buffer_free(&msg);
206: }
207:
208: static void
209: process(void)
210: {
211: u_int msg_len;
212: u_int buf_len;
213: u_int consumed;
214: u_int type;
215: u_char *cp;
216:
217: buf_len = buffer_len(&iqueue);
218: if (buf_len < 5)
219: return; /* Incomplete message. */
220: cp = buffer_ptr(&iqueue);
221: msg_len = get_u32(cp);
222: if (msg_len > MAX_MSG_LENGTH) {
223: error("bad message len %d", msg_len);
224: cleanup_exit(11);
225: }
226: if (buf_len < msg_len + 4)
227: return;
228: buffer_consume(&iqueue, 4);
229: buf_len -= 4;
230: type = buffer_get_char(&iqueue);
231: switch (type) {
232: case SSH_AGENTC_ADD_SMARTCARD_KEY:
233: debug("process_add");
234: process_add();
235: break;
236: case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
237: debug("process_del");
238: process_del();
239: break;
240: case SSH2_AGENTC_SIGN_REQUEST:
241: debug("process_sign");
242: process_sign();
243: break;
244: default:
245: error("Unknown message %d", type);
246: break;
247: }
248: /* discard the remaining bytes from the current packet */
249: if (buf_len < buffer_len(&iqueue)) {
250: error("iqueue grew unexpectedly");
251: cleanup_exit(255);
252: }
253: consumed = buf_len - buffer_len(&iqueue);
254: if (msg_len < consumed) {
255: error("msg_len %d < consumed %d", msg_len, consumed);
256: cleanup_exit(255);
257: }
258: if (msg_len > consumed)
259: buffer_consume(&iqueue, msg_len - consumed);
260: }
261:
262: void
263: cleanup_exit(int i)
264: {
265: /* XXX */
266: _exit(i);
267: }
268:
269: int
270: main(int argc, char **argv)
271: {
272: fd_set *rset, *wset;
273: int in, out, max, log_stderr = 0;
274: ssize_t len, olen, set_size;
275: SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
276: LogLevel log_level = SYSLOG_LEVEL_ERROR;
277: char buf[4*4096];
278: extern char *__progname;
279:
1.10 ! christos 280: ssh_malloc_init(); /* must be called before any mallocs */
1.1 adam 281: TAILQ_INIT(&pkcs11_keylist);
282: pkcs11_init(0);
283:
284: log_init(__progname, log_level, log_facility, log_stderr);
285:
286: in = STDIN_FILENO;
287: out = STDOUT_FILENO;
288:
289: max = 0;
290: if (in > max)
291: max = in;
292: if (out > max)
293: max = out;
294:
295: buffer_init(&iqueue);
296: buffer_init(&oqueue);
297:
298: set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1.9 christos 299: rset = xmalloc(set_size);
300: wset = xmalloc(set_size);
1.1 adam 301:
302: for (;;) {
303: memset(rset, 0, set_size);
304: memset(wset, 0, set_size);
305:
306: /*
307: * Ensure that we can read a full buffer and handle
308: * the worst-case length packet it can generate,
309: * otherwise apply backpressure by stopping reads.
310: */
311: if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
312: buffer_check_alloc(&oqueue, MAX_MSG_LENGTH))
313: FD_SET(in, rset);
314:
315: olen = buffer_len(&oqueue);
316: if (olen > 0)
317: FD_SET(out, wset);
318:
319: if (select(max+1, rset, wset, NULL, NULL) < 0) {
320: if (errno == EINTR)
321: continue;
322: error("select: %s", strerror(errno));
323: cleanup_exit(2);
324: }
325:
326: /* copy stdin to iqueue */
327: if (FD_ISSET(in, rset)) {
328: len = read(in, buf, sizeof buf);
329: if (len == 0) {
330: debug("read eof");
331: cleanup_exit(0);
332: } else if (len < 0) {
333: error("read: %s", strerror(errno));
334: cleanup_exit(1);
335: } else {
336: buffer_append(&iqueue, buf, len);
337: }
338: }
339: /* send oqueue to stdout */
340: if (FD_ISSET(out, wset)) {
341: len = write(out, buffer_ptr(&oqueue), olen);
342: if (len < 0) {
343: error("write: %s", strerror(errno));
344: cleanup_exit(1);
345: } else {
346: buffer_consume(&oqueue, len);
347: }
348: }
349:
350: /*
351: * Process requests from client if we can fit the results
352: * into the output buffer, otherwise stop processing input
353: * and let the output queue drain.
354: */
355: if (buffer_check_alloc(&oqueue, MAX_MSG_LENGTH))
356: process();
357: }
358: }
CVSweb <webmaster@jp.NetBSD.org>