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