1 /* $NetBSD: ssh-pkcs11-helper.c,v 1.19 2020/05/28 17:05:49 christos Exp $ */ 2 /* $OpenBSD: ssh-pkcs11-helper.c,v 1.23 2020/03/06 18:26:21 markus Exp $ */ 3 /* 4 * Copyright (c) 2010 Markus Friedl. All rights reserved. 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 #include "includes.h" 19 __RCSID("$NetBSD: ssh-pkcs11-helper.c,v 1.19 2020/05/28 17:05:49 christos Exp $"); 20 21 #include <sys/types.h> 22 #include <sys/queue.h> 23 #include <sys/time.h> 24 #include <sys/param.h> 25 26 #include <stdlib.h> 27 #include <errno.h> 28 #include <poll.h> 29 #include <stdarg.h> 30 #include <string.h> 31 #include <unistd.h> 32 33 #include "xmalloc.h" 34 #include "sshbuf.h" 35 #include "log.h" 36 #include "misc.h" 37 #include "sshkey.h" 38 #include "authfd.h" 39 #include "ssh-pkcs11.h" 40 #include "ssherr.h" 41 42 #ifdef WITH_OPENSSL 43 44 /* borrows code from sftp-server and ssh-agent */ 45 46 struct pkcs11_keyinfo { 47 struct sshkey *key; 48 char *providername, *label; 49 TAILQ_ENTRY(pkcs11_keyinfo) next; 50 }; 51 52 TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist; 53 54 #define MAX_MSG_LENGTH 10240 /*XXX*/ 55 56 /* input and output queue */ 57 struct sshbuf *iqueue; 58 struct sshbuf *oqueue; 59 60 static void 61 add_key(struct sshkey *k, char *name, char *label) 62 { 63 struct pkcs11_keyinfo *ki; 64 65 ki = xcalloc(1, sizeof(*ki)); 66 ki->providername = xstrdup(name); 67 ki->key = k; 68 ki->label = xstrdup(label); 69 TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next); 70 } 71 72 static void 73 del_keys_by_name(char *name) 74 { 75 struct pkcs11_keyinfo *ki, *nxt; 76 77 for (ki = TAILQ_FIRST(&pkcs11_keylist); ki; ki = nxt) { 78 nxt = TAILQ_NEXT(ki, next); 79 if (!strcmp(ki->providername, name)) { 80 TAILQ_REMOVE(&pkcs11_keylist, ki, next); 81 free(ki->providername); 82 free(ki->label); 83 sshkey_free(ki->key); 84 free(ki); 85 } 86 } 87 } 88 89 /* lookup matching 'private' key */ 90 static struct sshkey * 91 lookup_key(struct sshkey *k) 92 { 93 struct pkcs11_keyinfo *ki; 94 95 TAILQ_FOREACH(ki, &pkcs11_keylist, next) { 96 debug("check %p %s %s", ki, ki->providername, ki->label); 97 if (sshkey_equal(k, ki->key)) 98 return (ki->key); 99 } 100 return (NULL); 101 } 102 103 static void 104 send_msg(struct sshbuf *m) 105 { 106 int r; 107 108 if ((r = sshbuf_put_stringb(oqueue, m)) != 0) 109 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 110 } 111 112 static void 113 process_add(void) 114 { 115 char *name, *pin; 116 struct sshkey **keys = NULL; 117 int r, i, nkeys; 118 u_char *blob; 119 size_t blen; 120 struct sshbuf *msg; 121 char **labels = NULL; 122 123 if ((msg = sshbuf_new()) == NULL) 124 fatal("%s: sshbuf_new failed", __func__); 125 if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || 126 (r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0) 127 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 128 if ((nkeys = pkcs11_add_provider(name, pin, &keys, &labels)) > 0) { 129 if ((r = sshbuf_put_u8(msg, 130 SSH2_AGENT_IDENTITIES_ANSWER)) != 0 || 131 (r = sshbuf_put_u32(msg, nkeys)) != 0) 132 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 133 for (i = 0; i < nkeys; i++) { 134 if ((r = sshkey_to_blob(keys[i], &blob, &blen)) != 0) { 135 debug("%s: sshkey_to_blob: %s", 136 __func__, ssh_err(r)); 137 continue; 138 } 139 if ((r = sshbuf_put_string(msg, blob, blen)) != 0 || 140 (r = sshbuf_put_cstring(msg, labels[i])) != 0) 141 fatal("%s: buffer error: %s", 142 __func__, ssh_err(r)); 143 free(blob); 144 add_key(keys[i], name, labels[i]); 145 free(labels[i]); 146 } 147 } else { 148 if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0) 149 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 150 if ((r = sshbuf_put_u32(msg, -nkeys)) != 0) 151 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 152 } 153 free(labels); 154 free(keys); /* keys themselves are transferred to pkcs11_keylist */ 155 free(pin); 156 free(name); 157 send_msg(msg); 158 sshbuf_free(msg); 159 } 160 161 static void 162 process_del(void) 163 { 164 char *name, *pin; 165 struct sshbuf *msg; 166 int r; 167 168 if ((msg = sshbuf_new()) == NULL) 169 fatal("%s: sshbuf_new failed", __func__); 170 if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || 171 (r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0) 172 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 173 del_keys_by_name(name); 174 if ((r = sshbuf_put_u8(msg, pkcs11_del_provider(name) == 0 ? 175 SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE)) != 0) 176 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 177 free(pin); 178 free(name); 179 send_msg(msg); 180 sshbuf_free(msg); 181 } 182 183 static void 184 process_sign(void) 185 { 186 u_char *blob, *data, *signature = NULL; 187 size_t blen, dlen, slen = 0; 188 int r, ok = -1; 189 struct sshkey *key, *found; 190 struct sshbuf *msg; 191 192 /* XXX support SHA2 signature flags */ 193 if ((r = sshbuf_get_string(iqueue, &blob, &blen)) != 0 || 194 (r = sshbuf_get_string(iqueue, &data, &dlen)) != 0 || 195 (r = sshbuf_get_u32(iqueue, NULL)) != 0) 196 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 197 198 if ((r = sshkey_from_blob(blob, blen, &key)) != 0) 199 error("%s: sshkey_from_blob: %s", __func__, ssh_err(r)); 200 else { 201 if ((found = lookup_key(key)) != NULL) { 202 #ifdef WITH_OPENSSL 203 int ret; 204 205 if (key->type == KEY_RSA) { 206 slen = RSA_size(key->rsa); 207 signature = xmalloc(slen); 208 ret = RSA_private_encrypt(dlen, data, signature, 209 found->rsa, RSA_PKCS1_PADDING); 210 if (ret != -1) { 211 slen = ret; 212 ok = 0; 213 } 214 } else if (key->type == KEY_ECDSA) { 215 u_int xslen = ECDSA_size(key->ecdsa); 216 217 signature = xmalloc(xslen); 218 /* "The parameter type is ignored." */ 219 ret = ECDSA_sign(-1, data, dlen, signature, 220 &xslen, found->ecdsa); 221 if (ret != 0) 222 ok = 0; 223 else 224 error("%s: ECDSA_sign" 225 " returns %d", __func__, ret); 226 slen = xslen; 227 } else 228 error("%s: don't know how to sign with key " 229 "type %d", __func__, (int)key->type); 230 #endif /* WITH_OPENSSL */ 231 } 232 sshkey_free(key); 233 } 234 if ((msg = sshbuf_new()) == NULL) 235 fatal("%s: sshbuf_new failed", __func__); 236 if (ok == 0) { 237 if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 || 238 (r = sshbuf_put_string(msg, signature, slen)) != 0) 239 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 240 } else { 241 if ((r = sshbuf_put_u8(msg, SSH2_AGENT_FAILURE)) != 0) 242 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 243 } 244 free(data); 245 free(blob); 246 free(signature); 247 send_msg(msg); 248 sshbuf_free(msg); 249 } 250 251 static void 252 process(void) 253 { 254 u_int msg_len; 255 u_int buf_len; 256 u_int consumed; 257 u_char type; 258 const u_char *cp; 259 int r; 260 261 buf_len = sshbuf_len(iqueue); 262 if (buf_len < 5) 263 return; /* Incomplete message. */ 264 cp = sshbuf_ptr(iqueue); 265 msg_len = get_u32(cp); 266 if (msg_len > MAX_MSG_LENGTH) { 267 error("bad message len %d", msg_len); 268 cleanup_exit(11); 269 } 270 if (buf_len < msg_len + 4) 271 return; 272 if ((r = sshbuf_consume(iqueue, 4)) != 0 || 273 (r = sshbuf_get_u8(iqueue, &type)) != 0) 274 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 275 buf_len -= 4; 276 switch (type) { 277 case SSH_AGENTC_ADD_SMARTCARD_KEY: 278 debug("process_add"); 279 process_add(); 280 break; 281 case SSH_AGENTC_REMOVE_SMARTCARD_KEY: 282 debug("process_del"); 283 process_del(); 284 break; 285 case SSH2_AGENTC_SIGN_REQUEST: 286 debug("process_sign"); 287 process_sign(); 288 break; 289 default: 290 error("Unknown message %d", type); 291 break; 292 } 293 /* discard the remaining bytes from the current packet */ 294 if (buf_len < sshbuf_len(iqueue)) { 295 error("iqueue grew unexpectedly"); 296 cleanup_exit(255); 297 } 298 consumed = buf_len - sshbuf_len(iqueue); 299 if (msg_len < consumed) { 300 error("msg_len %d < consumed %d", msg_len, consumed); 301 cleanup_exit(255); 302 } 303 if (msg_len > consumed) { 304 if ((r = sshbuf_consume(iqueue, msg_len - consumed)) != 0) 305 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 306 } 307 } 308 309 void 310 cleanup_exit(int i) 311 { 312 /* XXX */ 313 _exit(i); 314 } 315 316 317 int 318 main(int argc, char **argv) 319 { 320 int r, ch, in, out, log_stderr = 0; 321 ssize_t len; 322 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 323 LogLevel log_level = SYSLOG_LEVEL_ERROR; 324 char buf[4*4096]; 325 extern char *__progname; 326 struct pollfd pfd[2]; 327 328 TAILQ_INIT(&pkcs11_keylist); 329 330 log_init(__progname, log_level, log_facility, log_stderr); 331 332 while ((ch = getopt(argc, argv, "v")) != -1) { 333 switch (ch) { 334 case 'v': 335 log_stderr = 1; 336 if (log_level == SYSLOG_LEVEL_ERROR) 337 log_level = SYSLOG_LEVEL_DEBUG1; 338 else if (log_level < SYSLOG_LEVEL_DEBUG3) 339 log_level++; 340 break; 341 default: 342 fprintf(stderr, "usage: %s [-v]\n", __progname); 343 exit(1); 344 } 345 } 346 347 log_init(__progname, log_level, log_facility, log_stderr); 348 349 pkcs11_init(0); 350 in = STDIN_FILENO; 351 out = STDOUT_FILENO; 352 353 if ((iqueue = sshbuf_new()) == NULL) 354 fatal("%s: sshbuf_new failed", __func__); 355 if ((oqueue = sshbuf_new()) == NULL) 356 fatal("%s: sshbuf_new failed", __func__); 357 358 while (1) { 359 memset(pfd, 0, sizeof(pfd)); 360 pfd[0].fd = in; 361 pfd[1].fd = out; 362 363 /* 364 * Ensure that we can read a full buffer and handle 365 * the worst-case length packet it can generate, 366 * otherwise apply backpressure by stopping reads. 367 */ 368 if ((r = sshbuf_check_reserve(iqueue, sizeof(buf))) == 0 && 369 (r = sshbuf_check_reserve(oqueue, MAX_MSG_LENGTH)) == 0) 370 pfd[0].events = POLLIN; 371 else if (r != SSH_ERR_NO_BUFFER_SPACE) 372 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 373 374 if (sshbuf_len(oqueue) > 0) 375 pfd[1].events = POLLOUT; 376 377 if ((r = poll(pfd, 2, -1 /* INFTIM */)) <= 0) { 378 if (r == 0 || errno == EINTR) 379 continue; 380 fatal("poll: %s", strerror(errno)); 381 } 382 383 /* copy stdin to iqueue */ 384 if ((pfd[0].revents & (POLLIN|POLLERR)) != 0) { 385 len = read(in, buf, sizeof buf); 386 if (len == 0) { 387 debug("read eof"); 388 cleanup_exit(0); 389 } else if (len < 0) { 390 error("read: %s", strerror(errno)); 391 cleanup_exit(1); 392 } else if ((r = sshbuf_put(iqueue, buf, len)) != 0) { 393 fatal("%s: buffer error: %s", 394 __func__, ssh_err(r)); 395 } 396 } 397 /* send oqueue to stdout */ 398 if ((pfd[1].revents & (POLLOUT|POLLHUP)) != 0) { 399 len = write(out, sshbuf_ptr(oqueue), 400 sshbuf_len(oqueue)); 401 if (len < 0) { 402 error("write: %s", strerror(errno)); 403 cleanup_exit(1); 404 } else if ((r = sshbuf_consume(oqueue, len)) != 0) { 405 fatal("%s: buffer error: %s", 406 __func__, ssh_err(r)); 407 } 408 } 409 410 /* 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. 414 */ 415 if ((r = sshbuf_check_reserve(oqueue, MAX_MSG_LENGTH)) == 0) 416 process(); 417 else if (r != SSH_ERR_NO_BUFFER_SPACE) 418 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 419 } 420 } 421 422 #else /* WITH_OPENSSL */ 423 void 424 cleanup_exit(int i) 425 { 426 _exit(i); 427 } 428 429 int 430 main(int argc, char **argv) 431 { 432 fprintf(stderr, "PKCS#11 code is not enabled\n"); 433 return 1; 434 } 435 #endif /* WITH_OPENSSL */ 436