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