1 /* $OpenBSD: ssh-pkcs11-client.c,v 1.17 2020/10/18 11:32:02 djm Exp $ */ 2 /* 3 * Copyright (c) 2010 Markus Friedl. All rights reserved. 4 * Copyright (c) 2014 Pedro Martelletto. 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 19 #include "includes.h" 20 21 #ifdef ENABLE_PKCS11 22 23 #include <sys/types.h> 24 #ifdef HAVE_SYS_TIME_H 25 # include <sys/time.h> 26 #endif 27 #include <sys/socket.h> 28 29 #include <stdarg.h> 30 #include <string.h> 31 #include <unistd.h> 32 #include <errno.h> 33 34 #include <openssl/ecdsa.h> 35 #include <openssl/rsa.h> 36 37 #include "openbsd-compat/openssl-compat.h" 38 39 #include "pathnames.h" 40 #include "xmalloc.h" 41 #include "sshbuf.h" 42 #include "log.h" 43 #include "misc.h" 44 #include "sshkey.h" 45 #include "authfd.h" 46 #include "atomicio.h" 47 #include "ssh-pkcs11.h" 48 #include "ssherr.h" 49 50 /* borrows code from sftp-server and ssh-agent */ 51 52 static int fd = -1; 53 static pid_t pid = -1; 54 55 static void 56 send_msg(struct sshbuf *m) 57 { 58 u_char buf[4]; 59 size_t mlen = sshbuf_len(m); 60 int r; 61 62 POKE_U32(buf, mlen); 63 if (atomicio(vwrite, fd, buf, 4) != 4 || 64 atomicio(vwrite, fd, sshbuf_mutable_ptr(m), 65 sshbuf_len(m)) != sshbuf_len(m)) 66 error("write to helper failed"); 67 if ((r = sshbuf_consume(m, mlen)) != 0) 68 fatal_fr(r, "consume"); 69 } 70 71 static int 72 recv_msg(struct sshbuf *m) 73 { 74 u_int l, len; 75 u_char c, buf[1024]; 76 int r; 77 78 if ((len = atomicio(read, fd, buf, 4)) != 4) { 79 error("read from helper failed: %u", len); 80 return (0); /* XXX */ 81 } 82 len = PEEK_U32(buf); 83 if (len > 256 * 1024) 84 fatal("response too long: %u", len); 85 /* read len bytes into m */ 86 sshbuf_reset(m); 87 while (len > 0) { 88 l = len; 89 if (l > sizeof(buf)) 90 l = sizeof(buf); 91 if (atomicio(read, fd, buf, l) != l) { 92 error("response from helper failed."); 93 return (0); /* XXX */ 94 } 95 if ((r = sshbuf_put(m, buf, l)) != 0) 96 fatal_fr(r, "sshbuf_put"); 97 len -= l; 98 } 99 if ((r = sshbuf_get_u8(m, &c)) != 0) 100 fatal_fr(r, "parse type"); 101 return c; 102 } 103 104 int 105 pkcs11_init(int interactive) 106 { 107 return (0); 108 } 109 110 void 111 pkcs11_terminate(void) 112 { 113 if (fd >= 0) 114 close(fd); 115 } 116 117 static int 118 rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) 119 { 120 struct sshkey *key = NULL; 121 struct sshbuf *msg = NULL; 122 u_char *blob = NULL, *signature = NULL; 123 size_t blen, slen = 0; 124 int r, ret = -1; 125 126 if (padding != RSA_PKCS1_PADDING) 127 goto fail; 128 key = sshkey_new(KEY_UNSPEC); 129 if (key == NULL) { 130 error_f("sshkey_new failed"); 131 goto fail; 132 } 133 key->type = KEY_RSA; 134 RSA_up_ref(rsa); 135 key->rsa = rsa; 136 if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) { 137 error_fr(r, "encode key"); 138 goto fail; 139 } 140 if ((msg = sshbuf_new()) == NULL) 141 fatal_f("sshbuf_new failed"); 142 if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || 143 (r = sshbuf_put_string(msg, blob, blen)) != 0 || 144 (r = sshbuf_put_string(msg, from, flen)) != 0 || 145 (r = sshbuf_put_u32(msg, 0)) != 0) 146 fatal_fr(r, "compose"); 147 send_msg(msg); 148 sshbuf_reset(msg); 149 150 if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) { 151 if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0) 152 fatal_fr(r, "parse"); 153 if (slen <= (size_t)RSA_size(rsa)) { 154 memcpy(to, signature, slen); 155 ret = slen; 156 } 157 free(signature); 158 } 159 fail: 160 free(blob); 161 sshkey_free(key); 162 sshbuf_free(msg); 163 return (ret); 164 } 165 166 #ifdef HAVE_EC_KEY_METHOD_NEW 167 static ECDSA_SIG * 168 ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, 169 const BIGNUM *rp, EC_KEY *ec) 170 { 171 struct sshkey *key = NULL; 172 struct sshbuf *msg = NULL; 173 ECDSA_SIG *ret = NULL; 174 const u_char *cp; 175 u_char *blob = NULL, *signature = NULL; 176 size_t blen, slen = 0; 177 int r, nid; 178 179 nid = sshkey_ecdsa_key_to_nid(ec); 180 if (nid < 0) { 181 error_f("couldn't get curve nid"); 182 goto fail; 183 } 184 185 key = sshkey_new(KEY_UNSPEC); 186 if (key == NULL) { 187 error_f("sshkey_new failed"); 188 goto fail; 189 } 190 key->ecdsa = ec; 191 key->ecdsa_nid = nid; 192 key->type = KEY_ECDSA; 193 EC_KEY_up_ref(ec); 194 195 if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) { 196 error_fr(r, "encode key"); 197 goto fail; 198 } 199 if ((msg = sshbuf_new()) == NULL) 200 fatal_f("sshbuf_new failed"); 201 if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || 202 (r = sshbuf_put_string(msg, blob, blen)) != 0 || 203 (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 || 204 (r = sshbuf_put_u32(msg, 0)) != 0) 205 fatal_fr(r, "compose"); 206 send_msg(msg); 207 sshbuf_reset(msg); 208 209 if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) { 210 if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0) 211 fatal_fr(r, "parse"); 212 cp = signature; 213 ret = d2i_ECDSA_SIG(NULL, &cp, slen); 214 free(signature); 215 } 216 217 fail: 218 free(blob); 219 sshkey_free(key); 220 sshbuf_free(msg); 221 return (ret); 222 } 223 #endif /* HAVE_EC_KEY_METHOD_NEW */ 224 225 static RSA_METHOD *helper_rsa; 226 #ifdef HAVE_EC_KEY_METHOD_NEW 227 static EC_KEY_METHOD *helper_ecdsa; 228 #endif /* HAVE_EC_KEY_METHOD_NEW */ 229 230 /* redirect private key crypto operations to the ssh-pkcs11-helper */ 231 static void 232 wrap_key(struct sshkey *k) 233 { 234 if (k->type == KEY_RSA) 235 RSA_set_method(k->rsa, helper_rsa); 236 #ifdef HAVE_EC_KEY_METHOD_NEW 237 else if (k->type == KEY_ECDSA) 238 EC_KEY_set_method(k->ecdsa, helper_ecdsa); 239 #endif /* HAVE_EC_KEY_METHOD_NEW */ 240 else 241 fatal_f("unknown key type"); 242 } 243 244 static int 245 pkcs11_start_helper_methods(void) 246 { 247 if (helper_rsa != NULL) 248 return (0); 249 250 #ifdef HAVE_EC_KEY_METHOD_NEW 251 int (*orig_sign)(int, const unsigned char *, int, unsigned char *, 252 unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL; 253 if (helper_ecdsa != NULL) 254 return (0); 255 helper_ecdsa = EC_KEY_METHOD_new(EC_KEY_OpenSSL()); 256 if (helper_ecdsa == NULL) 257 return (-1); 258 EC_KEY_METHOD_get_sign(helper_ecdsa, &orig_sign, NULL, NULL); 259 EC_KEY_METHOD_set_sign(helper_ecdsa, orig_sign, NULL, ecdsa_do_sign); 260 #endif /* HAVE_EC_KEY_METHOD_NEW */ 261 262 if ((helper_rsa = RSA_meth_dup(RSA_get_default_method())) == NULL) 263 fatal_f("RSA_meth_dup failed"); 264 if (!RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper") || 265 !RSA_meth_set_priv_enc(helper_rsa, rsa_encrypt)) 266 fatal_f("failed to prepare method"); 267 268 return (0); 269 } 270 271 static int 272 pkcs11_start_helper(void) 273 { 274 int pair[2]; 275 char *helper, *verbosity = NULL; 276 277 if (log_level_get() >= SYSLOG_LEVEL_DEBUG1) 278 verbosity = "-vvv"; 279 280 if (pkcs11_start_helper_methods() == -1) { 281 error("pkcs11_start_helper_methods failed"); 282 return (-1); 283 } 284 285 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { 286 error("socketpair: %s", strerror(errno)); 287 return (-1); 288 } 289 if ((pid = fork()) == -1) { 290 error("fork: %s", strerror(errno)); 291 return (-1); 292 } else if (pid == 0) { 293 if ((dup2(pair[1], STDIN_FILENO) == -1) || 294 (dup2(pair[1], STDOUT_FILENO) == -1)) { 295 fprintf(stderr, "dup2: %s\n", strerror(errno)); 296 _exit(1); 297 } 298 close(pair[0]); 299 close(pair[1]); 300 helper = getenv("SSH_PKCS11_HELPER"); 301 if (helper == NULL || strlen(helper) == 0) 302 helper = _PATH_SSH_PKCS11_HELPER; 303 debug_f("starting %s %s", helper, 304 verbosity == NULL ? "" : verbosity); 305 execlp(helper, helper, verbosity, (char *)NULL); 306 fprintf(stderr, "exec: %s: %s\n", helper, strerror(errno)); 307 _exit(1); 308 } 309 close(pair[1]); 310 fd = pair[0]; 311 return (0); 312 } 313 314 int 315 pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, 316 char ***labelsp) 317 { 318 struct sshkey *k; 319 int r, type; 320 u_char *blob; 321 char *label; 322 size_t blen; 323 u_int nkeys, i; 324 struct sshbuf *msg; 325 326 if (fd < 0 && pkcs11_start_helper() < 0) 327 return (-1); 328 329 if ((msg = sshbuf_new()) == NULL) 330 fatal_f("sshbuf_new failed"); 331 if ((r = sshbuf_put_u8(msg, SSH_AGENTC_ADD_SMARTCARD_KEY)) != 0 || 332 (r = sshbuf_put_cstring(msg, name)) != 0 || 333 (r = sshbuf_put_cstring(msg, pin)) != 0) 334 fatal_fr(r, "compose"); 335 send_msg(msg); 336 sshbuf_reset(msg); 337 338 type = recv_msg(msg); 339 if (type == SSH2_AGENT_IDENTITIES_ANSWER) { 340 if ((r = sshbuf_get_u32(msg, &nkeys)) != 0) 341 fatal_fr(r, "parse nkeys"); 342 *keysp = xcalloc(nkeys, sizeof(struct sshkey *)); 343 if (labelsp) 344 *labelsp = xcalloc(nkeys, sizeof(char *)); 345 for (i = 0; i < nkeys; i++) { 346 /* XXX clean up properly instead of fatal() */ 347 if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 || 348 (r = sshbuf_get_cstring(msg, &label, NULL)) != 0) 349 fatal_fr(r, "parse key"); 350 if ((r = sshkey_from_blob(blob, blen, &k)) != 0) 351 fatal_fr(r, "decode key"); 352 wrap_key(k); 353 (*keysp)[i] = k; 354 if (labelsp) 355 (*labelsp)[i] = label; 356 else 357 free(label); 358 free(blob); 359 } 360 } else if (type == SSH2_AGENT_FAILURE) { 361 if ((r = sshbuf_get_u32(msg, &nkeys)) != 0) 362 nkeys = -1; 363 } else { 364 nkeys = -1; 365 } 366 sshbuf_free(msg); 367 return (nkeys); 368 } 369 370 int 371 pkcs11_del_provider(char *name) 372 { 373 int r, ret = -1; 374 struct sshbuf *msg; 375 376 if ((msg = sshbuf_new()) == NULL) 377 fatal_f("sshbuf_new failed"); 378 if ((r = sshbuf_put_u8(msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY)) != 0 || 379 (r = sshbuf_put_cstring(msg, name)) != 0 || 380 (r = sshbuf_put_cstring(msg, "")) != 0) 381 fatal_fr(r, "compose"); 382 send_msg(msg); 383 sshbuf_reset(msg); 384 385 if (recv_msg(msg) == SSH_AGENT_SUCCESS) 386 ret = 0; 387 sshbuf_free(msg); 388 return (ret); 389 } 390 391 #endif /* ENABLE_PKCS11 */ 392