1 /* $OpenBSD: ssh-pkcs11-helper.c,v 1.25 2021/08/11 05:20:17 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 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 %s %s %s", sshkey_type(ki->key), 102 ki->providername, ki->label); 103 if (sshkey_equal(k, ki->key)) 104 return (ki->key); 105 } 106 return (NULL); 107 } 108 109 static void 110 send_msg(struct sshbuf *m) 111 { 112 int r; 113 114 if ((r = sshbuf_put_stringb(oqueue, m)) != 0) 115 fatal_fr(r, "enqueue"); 116 } 117 118 static void 119 process_add(void) 120 { 121 char *name, *pin; 122 struct sshkey **keys = NULL; 123 int r, i, nkeys; 124 u_char *blob; 125 size_t blen; 126 struct sshbuf *msg; 127 char **labels = NULL; 128 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"); 142 continue; 143 } 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"); 147 free(blob); 148 add_key(keys[i], name, labels[i]); 149 free(labels[i]); 150 } 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"); 154 free(labels); 155 free(keys); /* keys themselves are transferred to pkcs11_keylist */ 156 free(pin); 157 free(name); 158 send_msg(msg); 159 sshbuf_free(msg); 160 } 161 162 static void 163 process_del(void) 164 { 165 char *name, *pin; 166 struct sshbuf *msg; 167 int r; 168 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"); 178 free(pin); 179 free(name); 180 send_msg(msg); 181 sshbuf_free(msg); 182 } 183 184 static void 185 process_sign(void) 186 { 187 u_char *blob, *data, *signature = NULL; 188 size_t blen, dlen, slen = 0; 189 int r, ok = -1; 190 struct sshkey *key, *found; 191 struct sshbuf *msg; 192 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"); 198 199 if ((r = sshkey_from_blob(blob, blen, &key)) != 0) 200 fatal_fr(r, "decode key"); 201 else { 202 if ((found = lookup_key(key)) != NULL) { 203 #ifdef WITH_OPENSSL 204 int ret; 205 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); 211 if (ret != -1) { 212 slen = ret; 213 ok = 0; 214 } 215 #ifdef OPENSSL_HAS_ECC 216 } else if (key->type == KEY_ECDSA) { 217 u_int xslen = ECDSA_size(key->ecdsa); 218 219 signature = xmalloc(xslen); 220 /* "The parameter type is ignored." */ 221 ret = ECDSA_sign(-1, data, dlen, signature, 222 &xslen, found->ecdsa); 223 if (ret != 0) 224 ok = 0; 225 else 226 error_f("ECDSA_sign returned %d", ret); 227 slen = xslen; 228 #endif /* OPENSSL_HAS_ECC */ 229 } else 230 error_f("don't know how to sign with key " 231 "type %d", (int)key->type); 232 #endif /* WITH_OPENSSL */ 233 } 234 sshkey_free(key); 235 } 236 if ((msg = sshbuf_new()) == NULL) 237 fatal_f("sshbuf_new failed"); 238 if (ok == 0) { 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"); 242 } else { 243 if ((r = sshbuf_put_u8(msg, SSH2_AGENT_FAILURE)) != 0) 244 fatal_fr(r, "compose failure response"); 245 } 246 free(data); 247 free(blob); 248 free(signature); 249 send_msg(msg); 250 sshbuf_free(msg); 251 } 252 253 static void 254 process(void) 255 { 256 u_int msg_len; 257 u_int buf_len; 258 u_int consumed; 259 u_char type; 260 const u_char *cp; 261 int r; 262 263 buf_len = sshbuf_len(iqueue); 264 if (buf_len < 5) 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); 270 cleanup_exit(11); 271 } 272 if (buf_len < msg_len + 4) 273 return; 274 if ((r = sshbuf_consume(iqueue, 4)) != 0 || 275 (r = sshbuf_get_u8(iqueue, &type)) != 0) 276 fatal_fr(r, "parse type/len"); 277 buf_len -= 4; 278 switch (type) { 279 case SSH_AGENTC_ADD_SMARTCARD_KEY: 280 debug("process_add"); 281 process_add(); 282 break; 283 case SSH_AGENTC_REMOVE_SMARTCARD_KEY: 284 debug("process_del"); 285 process_del(); 286 break; 287 case SSH2_AGENTC_SIGN_REQUEST: 288 debug("process_sign"); 289 process_sign(); 290 break; 291 default: 292 error("Unknown message %d", type); 293 break; 294 } 295 /* discard the remaining bytes from the current packet */ 296 if (buf_len < sshbuf_len(iqueue)) { 297 error("iqueue grew unexpectedly"); 298 cleanup_exit(255); 299 } 300 consumed = buf_len - sshbuf_len(iqueue); 301 if (msg_len < consumed) { 302 error("msg_len %d < consumed %d", msg_len, consumed); 303 cleanup_exit(255); 304 } 305 if (msg_len > consumed) { 306 if ((r = sshbuf_consume(iqueue, msg_len - consumed)) != 0) 307 fatal_fr(r, "consume"); 308 } 309 } 310 311 void 312 cleanup_exit(int i) 313 { 314 /* XXX */ 315 _exit(i); 316 } 317 318 319 int 320 main(int argc, char **argv) 321 { 322 int r, ch, in, out, log_stderr = 0; 323 ssize_t len; 324 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 325 LogLevel log_level = SYSLOG_LEVEL_ERROR; 326 char buf[4*4096]; 327 extern char *__progname; 328 struct pollfd pfd[2]; 329 330 __progname = ssh_get_progname(argv[0]); 331 seed_rng(); 332 TAILQ_INIT(&pkcs11_keylist); 333 334 log_init(__progname, log_level, log_facility, log_stderr); 335 336 while ((ch = getopt(argc, argv, "v")) != -1) { 337 switch (ch) { 338 case 'v': 339 log_stderr = 1; 340 if (log_level == SYSLOG_LEVEL_ERROR) 341 log_level = SYSLOG_LEVEL_DEBUG1; 342 else if (log_level < SYSLOG_LEVEL_DEBUG3) 343 log_level++; 344 break; 345 default: 346 fprintf(stderr, "usage: %s [-v]\n", __progname); 347 exit(1); 348 } 349 } 350 351 log_init(__progname, log_level, log_facility, log_stderr); 352 353 pkcs11_init(0); 354 in = STDIN_FILENO; 355 out = STDOUT_FILENO; 356 357 if ((iqueue = sshbuf_new()) == NULL) 358 fatal_f("sshbuf_new failed"); 359 if ((oqueue = sshbuf_new()) == NULL) 360 fatal_f("sshbuf_new failed"); 361 362 while (1) { 363 memset(pfd, 0, sizeof(pfd)); 364 pfd[0].fd = in; 365 pfd[1].fd = out; 366 367 /* 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. 371 */ 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"); 377 378 if (sshbuf_len(oqueue) > 0) 379 pfd[1].events = POLLOUT; 380 381 if ((r = poll(pfd, 2, -1 /* INFTIM */)) <= 0) { 382 if (r == 0 || errno == EINTR) 383 continue; 384 fatal("poll: %s", strerror(errno)); 385 } 386 387 /* copy stdin to iqueue */ 388 if ((pfd[0].revents & (POLLIN|POLLERR)) != 0) { 389 len = read(in, buf, sizeof buf); 390 if (len == 0) { 391 debug("read eof"); 392 cleanup_exit(0); 393 } else if (len < 0) { 394 error("read: %s", strerror(errno)); 395 cleanup_exit(1); 396 } else if ((r = sshbuf_put(iqueue, buf, len)) != 0) 397 fatal_fr(r, "sshbuf_put"); 398 } 399 /* send oqueue to stdout */ 400 if ((pfd[1].revents & (POLLOUT|POLLHUP)) != 0) { 401 len = write(out, sshbuf_ptr(oqueue), 402 sshbuf_len(oqueue)); 403 if (len < 0) { 404 error("write: %s", strerror(errno)); 405 cleanup_exit(1); 406 } else if ((r = sshbuf_consume(oqueue, len)) != 0) 407 fatal_fr(r, "consume"); 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_fr(r, "reserve"); 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 #else /* ENABLE_PKCS11 */ 437 int 438 main(int argc, char **argv) 439 { 440 extern char *__progname; 441 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"); 445 } 446 #endif /* ENABLE_PKCS11 */ 447