1 /* $OpenBSD: ssh-pkcs11-helper.c,v 1.26 2021/11/18 03:31:44 djm Exp $ */
3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
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.
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.
20 #include <sys/types.h>
21 #ifdef HAVE_SYS_TIME_H
22 # include <sys/time.h>
25 #include "openbsd-compat/sys-queue.h"
42 #include "ssh-pkcs11.h"
49 /* borrows code from sftp-server and ssh-agent */
51 struct pkcs11_keyinfo
{
53 char *providername
, *label
;
54 TAILQ_ENTRY(pkcs11_keyinfo
) next
;
57 TAILQ_HEAD(, pkcs11_keyinfo
) pkcs11_keylist
;
59 #define MAX_MSG_LENGTH 10240 /*XXX*/
61 /* input and output queue */
62 struct sshbuf
*iqueue
;
63 struct sshbuf
*oqueue
;
66 add_key(struct sshkey
*k
, char *name
, char *label
)
68 struct pkcs11_keyinfo
*ki
;
70 ki
= xcalloc(1, sizeof(*ki
));
71 ki
->providername
= xstrdup(name
);
73 ki
->label
= xstrdup(label
);
74 TAILQ_INSERT_TAIL(&pkcs11_keylist
, ki
, next
);
78 del_keys_by_name(char *name
)
80 struct pkcs11_keyinfo
*ki
, *nxt
;
82 for (ki
= TAILQ_FIRST(&pkcs11_keylist
); ki
; ki
= nxt
) {
83 nxt
= TAILQ_NEXT(ki
, next
);
84 if (!strcmp(ki
->providername
, name
)) {
85 TAILQ_REMOVE(&pkcs11_keylist
, ki
, next
);
86 free(ki
->providername
);
94 /* lookup matching 'private' key */
95 static struct sshkey
*
96 lookup_key(struct sshkey
*k
)
98 struct pkcs11_keyinfo
*ki
;
100 TAILQ_FOREACH(ki
, &pkcs11_keylist
, next
) {
101 debug("check %s %s %s", sshkey_type(ki
->key
),
102 ki
->providername
, ki
->label
);
103 if (sshkey_equal(k
, ki
->key
))
110 send_msg(struct sshbuf
*m
)
114 if ((r
= sshbuf_put_stringb(oqueue
, m
)) != 0)
115 fatal_fr(r
, "enqueue");
122 struct sshkey
**keys
= NULL
;
127 char **labels
= NULL
;
129 if ((msg
= sshbuf_new()) == NULL
)
130 fatal_f("sshbuf_new failed");
131 if ((r
= sshbuf_get_cstring(iqueue
, &name
, NULL
)) != 0 ||
132 (r
= sshbuf_get_cstring(iqueue
, &pin
, NULL
)) != 0)
133 fatal_fr(r
, "parse");
134 if ((nkeys
= pkcs11_add_provider(name
, pin
, &keys
, &labels
)) > 0) {
135 if ((r
= sshbuf_put_u8(msg
,
136 SSH2_AGENT_IDENTITIES_ANSWER
)) != 0 ||
137 (r
= sshbuf_put_u32(msg
, nkeys
)) != 0)
138 fatal_fr(r
, "compose");
139 for (i
= 0; i
< nkeys
; i
++) {
140 if ((r
= sshkey_to_blob(keys
[i
], &blob
, &blen
)) != 0) {
141 debug_fr(r
, "encode key");
144 if ((r
= sshbuf_put_string(msg
, blob
, blen
)) != 0 ||
145 (r
= sshbuf_put_cstring(msg
, labels
[i
])) != 0)
146 fatal_fr(r
, "compose key");
148 add_key(keys
[i
], name
, labels
[i
]);
151 } else if ((r
= sshbuf_put_u8(msg
, SSH_AGENT_FAILURE
)) != 0 ||
152 (r
= sshbuf_put_u32(msg
, -nkeys
)) != 0)
153 fatal_fr(r
, "compose");
155 free(keys
); /* keys themselves are transferred to pkcs11_keylist */
169 if ((msg
= sshbuf_new()) == NULL
)
170 fatal_f("sshbuf_new failed");
171 if ((r
= sshbuf_get_cstring(iqueue
, &name
, NULL
)) != 0 ||
172 (r
= sshbuf_get_cstring(iqueue
, &pin
, NULL
)) != 0)
173 fatal_fr(r
, "parse");
174 del_keys_by_name(name
);
175 if ((r
= sshbuf_put_u8(msg
, pkcs11_del_provider(name
) == 0 ?
176 SSH_AGENT_SUCCESS
: SSH_AGENT_FAILURE
)) != 0)
177 fatal_fr(r
, "compose");
187 u_char
*blob
, *data
, *signature
= NULL
;
188 size_t blen
, dlen
, slen
= 0;
190 struct sshkey
*key
, *found
;
193 /* XXX support SHA2 signature flags */
194 if ((r
= sshbuf_get_string(iqueue
, &blob
, &blen
)) != 0 ||
195 (r
= sshbuf_get_string(iqueue
, &data
, &dlen
)) != 0 ||
196 (r
= sshbuf_get_u32(iqueue
, NULL
)) != 0)
197 fatal_fr(r
, "parse");
199 if ((r
= sshkey_from_blob(blob
, blen
, &key
)) != 0)
200 fatal_fr(r
, "decode key");
202 if ((found
= lookup_key(key
)) != NULL
) {
206 if (key
->type
== KEY_RSA
) {
207 slen
= RSA_size(key
->rsa
);
208 signature
= xmalloc(slen
);
209 ret
= RSA_private_encrypt(dlen
, data
, signature
,
210 found
->rsa
, RSA_PKCS1_PADDING
);
215 #ifdef OPENSSL_HAS_ECC
216 } else if (key
->type
== KEY_ECDSA
) {
217 u_int xslen
= ECDSA_size(key
->ecdsa
);
219 signature
= xmalloc(xslen
);
220 /* "The parameter type is ignored." */
221 ret
= ECDSA_sign(-1, data
, dlen
, signature
,
222 &xslen
, found
->ecdsa
);
226 error_f("ECDSA_sign returned %d", ret
);
228 #endif /* OPENSSL_HAS_ECC */
230 error_f("don't know how to sign with key "
231 "type %d", (int)key
->type
);
232 #endif /* WITH_OPENSSL */
236 if ((msg
= sshbuf_new()) == NULL
)
237 fatal_f("sshbuf_new failed");
239 if ((r
= sshbuf_put_u8(msg
, SSH2_AGENT_SIGN_RESPONSE
)) != 0 ||
240 (r
= sshbuf_put_string(msg
, signature
, slen
)) != 0)
241 fatal_fr(r
, "compose response");
243 if ((r
= sshbuf_put_u8(msg
, SSH2_AGENT_FAILURE
)) != 0)
244 fatal_fr(r
, "compose failure response");
263 buf_len
= sshbuf_len(iqueue
);
265 return; /* Incomplete message. */
266 cp
= sshbuf_ptr(iqueue
);
267 msg_len
= get_u32(cp
);
268 if (msg_len
> MAX_MSG_LENGTH
) {
269 error("bad message len %d", msg_len
);
272 if (buf_len
< msg_len
+ 4)
274 if ((r
= sshbuf_consume(iqueue
, 4)) != 0 ||
275 (r
= sshbuf_get_u8(iqueue
, &type
)) != 0)
276 fatal_fr(r
, "parse type/len");
279 case SSH_AGENTC_ADD_SMARTCARD_KEY
:
280 debug("process_add");
283 case SSH_AGENTC_REMOVE_SMARTCARD_KEY
:
284 debug("process_del");
287 case SSH2_AGENTC_SIGN_REQUEST
:
288 debug("process_sign");
292 error("Unknown message %d", type
);
295 /* discard the remaining bytes from the current packet */
296 if (buf_len
< sshbuf_len(iqueue
)) {
297 error("iqueue grew unexpectedly");
300 consumed
= buf_len
- sshbuf_len(iqueue
);
301 if (msg_len
< consumed
) {
302 error("msg_len %d < consumed %d", msg_len
, consumed
);
305 if (msg_len
> consumed
) {
306 if ((r
= sshbuf_consume(iqueue
, msg_len
- consumed
)) != 0)
307 fatal_fr(r
, "consume");
320 main(int argc
, char **argv
)
322 int r
, ch
, in
, out
, log_stderr
= 0;
324 SyslogFacility log_facility
= SYSLOG_FACILITY_AUTH
;
325 LogLevel log_level
= SYSLOG_LEVEL_ERROR
;
327 extern char *__progname
;
328 struct pollfd pfd
[2];
330 __progname
= ssh_get_progname(argv
[0]);
332 TAILQ_INIT(&pkcs11_keylist
);
334 log_init(__progname
, log_level
, log_facility
, log_stderr
);
336 while ((ch
= getopt(argc
, argv
, "v")) != -1) {
340 if (log_level
== SYSLOG_LEVEL_ERROR
)
341 log_level
= SYSLOG_LEVEL_DEBUG1
;
342 else if (log_level
< SYSLOG_LEVEL_DEBUG3
)
346 fprintf(stderr
, "usage: %s [-v]\n", __progname
);
351 log_init(__progname
, log_level
, log_facility
, log_stderr
);
357 if ((iqueue
= sshbuf_new()) == NULL
)
358 fatal_f("sshbuf_new failed");
359 if ((oqueue
= sshbuf_new()) == NULL
)
360 fatal_f("sshbuf_new failed");
363 memset(pfd
, 0, sizeof(pfd
));
368 * Ensure that we can read a full buffer and handle
369 * the worst-case length packet it can generate,
370 * otherwise apply backpressure by stopping reads.
372 if ((r
= sshbuf_check_reserve(iqueue
, sizeof(buf
))) == 0 &&
373 (r
= sshbuf_check_reserve(oqueue
, MAX_MSG_LENGTH
)) == 0)
374 pfd
[0].events
= POLLIN
;
375 else if (r
!= SSH_ERR_NO_BUFFER_SPACE
)
376 fatal_fr(r
, "reserve");
378 if (sshbuf_len(oqueue
) > 0)
379 pfd
[1].events
= POLLOUT
;
381 if ((r
= poll(pfd
, 2, -1 /* INFTIM */)) <= 0) {
382 if (r
== 0 || errno
== EINTR
)
384 fatal("poll: %s", strerror(errno
));
387 /* copy stdin to iqueue */
388 if ((pfd
[0].revents
& (POLLIN
|POLLHUP
|POLLERR
)) != 0) {
389 len
= read(in
, buf
, sizeof buf
);
393 } else if (len
< 0) {
394 error("read: %s", strerror(errno
));
396 } else if ((r
= sshbuf_put(iqueue
, buf
, len
)) != 0)
397 fatal_fr(r
, "sshbuf_put");
399 /* send oqueue to stdout */
400 if ((pfd
[1].revents
& (POLLOUT
|POLLHUP
)) != 0) {
401 len
= write(out
, sshbuf_ptr(oqueue
),
404 error("write: %s", strerror(errno
));
406 } else if ((r
= sshbuf_consume(oqueue
, len
)) != 0)
407 fatal_fr(r
, "consume");
411 * Process requests from client if we can fit the results
412 * into the output buffer, otherwise stop processing input
413 * and let the output queue drain.
415 if ((r
= sshbuf_check_reserve(oqueue
, MAX_MSG_LENGTH
)) == 0)
417 else if (r
!= SSH_ERR_NO_BUFFER_SPACE
)
418 fatal_fr(r
, "reserve");
422 #else /* WITH_OPENSSL */
430 main(int argc
, char **argv
)
432 fprintf(stderr
, "PKCS#11 code is not enabled\n");
435 #endif /* WITH_OPENSSL */
436 #else /* ENABLE_PKCS11 */
438 main(int argc
, char **argv
)
440 extern char *__progname
;
442 __progname
= ssh_get_progname(argv
[0]);
443 log_init(__progname
, SYSLOG_LEVEL_ERROR
, SYSLOG_FACILITY_AUTH
, 0);
444 fatal("PKCS#11 support disabled at compile time");
446 #endif /* ENABLE_PKCS11 */