Home | History | Annotate | Line # | Download | only in dist
ssh-pkcs11-client.c revision 1.20
      1  1.14  pgoyette /*	$NetBSD: ssh-pkcs11-client.c,v 1.20 2024/09/24 21:32:19 christos Exp $	*/
      2  1.20  christos /* $OpenBSD: ssh-pkcs11-client.c,v 1.20 2024/08/15 00:51:51 djm Exp $ */
      3  1.17  christos 
      4   1.1      adam /*
      5   1.1      adam  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
      6  1.15  christos  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
      7   1.1      adam  *
      8   1.1      adam  * Permission to use, copy, modify, and distribute this software for any
      9   1.1      adam  * purpose with or without fee is hereby granted, provided that the above
     10   1.1      adam  * copyright notice and this permission notice appear in all copies.
     11   1.1      adam  *
     12   1.1      adam  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     13   1.1      adam  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     14   1.1      adam  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     15   1.1      adam  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     16   1.1      adam  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     17   1.1      adam  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     18   1.1      adam  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     19   1.1      adam  */
     20   1.2      adam #include "includes.h"
     21  1.14  pgoyette __RCSID("$NetBSD: ssh-pkcs11-client.c,v 1.20 2024/09/24 21:32:19 christos Exp $");
     22   1.1      adam 
     23   1.1      adam #include <sys/types.h>
     24   1.1      adam #include <sys/time.h>
     25   1.1      adam #include <sys/socket.h>
     26   1.1      adam 
     27   1.1      adam #include <stdarg.h>
     28   1.1      adam #include <string.h>
     29   1.1      adam #include <unistd.h>
     30   1.1      adam #include <errno.h>
     31  1.18  christos #include <limits.h>
     32   1.1      adam 
     33  1.15  christos #include <openssl/ecdsa.h>
     34   1.5  christos #include <openssl/rsa.h>
     35   1.5  christos 
     36   1.1      adam #include "pathnames.h"
     37   1.1      adam #include "xmalloc.h"
     38  1.13  christos #include "sshbuf.h"
     39   1.1      adam #include "log.h"
     40   1.1      adam #include "misc.h"
     41  1.13  christos #include "sshkey.h"
     42   1.1      adam #include "authfd.h"
     43   1.1      adam #include "atomicio.h"
     44   1.1      adam #include "ssh-pkcs11.h"
     45  1.13  christos #include "ssherr.h"
     46   1.1      adam 
     47   1.1      adam /* borrows code from sftp-server and ssh-agent */
     48   1.1      adam 
     49  1.18  christos /*
     50  1.18  christos  * Maintain a list of ssh-pkcs11-helper subprocesses. These may be looked up
     51  1.18  christos  * by provider path or their unique EC/RSA METHOD pointers.
     52  1.18  christos  */
     53  1.18  christos struct helper {
     54  1.18  christos 	char *path;
     55  1.18  christos 	pid_t pid;
     56  1.18  christos 	int fd;
     57  1.18  christos 	RSA_METHOD *rsa_meth;
     58  1.18  christos 	EC_KEY_METHOD *ec_meth;
     59  1.18  christos 	int (*rsa_finish)(RSA *rsa);
     60  1.18  christos 	void (*ec_finish)(EC_KEY *key);
     61  1.18  christos 	size_t nrsa, nec; /* number of active keys of each type */
     62  1.18  christos };
     63  1.18  christos static struct helper **helpers;
     64  1.18  christos static size_t nhelpers;
     65  1.18  christos 
     66  1.18  christos static struct helper *
     67  1.18  christos helper_by_provider(const char *path)
     68  1.18  christos {
     69  1.18  christos 	size_t i;
     70  1.18  christos 
     71  1.18  christos 	for (i = 0; i < nhelpers; i++) {
     72  1.18  christos 		if (helpers[i] == NULL || helpers[i]->path == NULL ||
     73  1.18  christos 		    helpers[i]->fd == -1)
     74  1.18  christos 			continue;
     75  1.18  christos 		if (strcmp(helpers[i]->path, path) == 0)
     76  1.18  christos 			return helpers[i];
     77  1.18  christos 	}
     78  1.18  christos 	return NULL;
     79  1.18  christos }
     80  1.18  christos 
     81  1.18  christos static struct helper *
     82  1.18  christos helper_by_rsa(const RSA *rsa)
     83  1.18  christos {
     84  1.18  christos 	size_t i;
     85  1.18  christos 	const RSA_METHOD *meth;
     86  1.18  christos 
     87  1.18  christos 	if ((meth = RSA_get_method(rsa)) == NULL)
     88  1.18  christos 		return NULL;
     89  1.18  christos 	for (i = 0; i < nhelpers; i++) {
     90  1.18  christos 		if (helpers[i] != NULL && helpers[i]->rsa_meth == meth)
     91  1.18  christos 			return helpers[i];
     92  1.18  christos 	}
     93  1.18  christos 	return NULL;
     94  1.18  christos 
     95  1.18  christos }
     96  1.18  christos 
     97  1.18  christos static struct helper *
     98  1.18  christos helper_by_ec(const EC_KEY *ec)
     99  1.18  christos {
    100  1.18  christos 	size_t i;
    101  1.18  christos 	const EC_KEY_METHOD *meth;
    102  1.18  christos 
    103  1.18  christos 	if ((meth = EC_KEY_get_method(ec)) == NULL)
    104  1.18  christos 		return NULL;
    105  1.18  christos 	for (i = 0; i < nhelpers; i++) {
    106  1.18  christos 		if (helpers[i] != NULL && helpers[i]->ec_meth == meth)
    107  1.18  christos 			return helpers[i];
    108  1.18  christos 	}
    109  1.18  christos 	return NULL;
    110  1.18  christos 
    111  1.18  christos }
    112  1.18  christos 
    113  1.18  christos static void
    114  1.18  christos helper_free(struct helper *helper)
    115  1.18  christos {
    116  1.18  christos 	size_t i;
    117  1.18  christos 	int found = 0;
    118  1.18  christos 
    119  1.18  christos 	if (helper == NULL)
    120  1.18  christos 		return;
    121  1.18  christos 	if (helper->path == NULL || helper->ec_meth == NULL ||
    122  1.18  christos 	    helper->rsa_meth == NULL)
    123  1.18  christos 		fatal_f("inconsistent helper");
    124  1.18  christos 	debug3_f("free helper for provider %s", helper->path);
    125  1.18  christos 	for (i = 0; i < nhelpers; i++) {
    126  1.18  christos 		if (helpers[i] == helper) {
    127  1.18  christos 			if (found)
    128  1.18  christos 				fatal_f("helper recorded more than once");
    129  1.18  christos 			found = 1;
    130  1.18  christos 		}
    131  1.18  christos 		else if (found)
    132  1.18  christos 			helpers[i - 1] = helpers[i];
    133  1.18  christos 	}
    134  1.18  christos 	if (found) {
    135  1.18  christos 		helpers = xrecallocarray(helpers, nhelpers,
    136  1.18  christos 		    nhelpers - 1, sizeof(*helpers));
    137  1.18  christos 		nhelpers--;
    138  1.18  christos 	}
    139  1.18  christos 	free(helper->path);
    140  1.18  christos 	EC_KEY_METHOD_free(helper->ec_meth);
    141  1.18  christos 	RSA_meth_free(helper->rsa_meth);
    142  1.18  christos 	free(helper);
    143  1.18  christos }
    144  1.18  christos 
    145  1.18  christos static void
    146  1.18  christos helper_terminate(struct helper *helper)
    147  1.18  christos {
    148  1.18  christos 	if (helper == NULL) {
    149  1.18  christos 		return;
    150  1.18  christos 	} else if (helper->fd == -1) {
    151  1.18  christos 		debug3_f("already terminated");
    152  1.18  christos 	} else {
    153  1.18  christos 		debug3_f("terminating helper for %s; "
    154  1.18  christos 		    "remaining %zu RSA %zu ECDSA",
    155  1.18  christos 		    helper->path, helper->nrsa, helper->nec);
    156  1.18  christos 		close(helper->fd);
    157  1.18  christos 		/* XXX waitpid() */
    158  1.18  christos 		helper->fd = -1;
    159  1.18  christos 		helper->pid = -1;
    160  1.18  christos 	}
    161  1.18  christos 	/*
    162  1.18  christos 	 * Don't delete the helper entry until there are no remaining keys
    163  1.18  christos 	 * that reference it. Otherwise, any signing operation would call
    164  1.18  christos 	 * a free'd METHOD pointer and that would be bad.
    165  1.18  christos 	 */
    166  1.18  christos 	if (helper->nrsa == 0 && helper->nec == 0)
    167  1.18  christos 		helper_free(helper);
    168  1.18  christos }
    169   1.1      adam 
    170   1.1      adam static void
    171  1.18  christos send_msg(int fd, struct sshbuf *m)
    172   1.1      adam {
    173   1.1      adam 	u_char buf[4];
    174  1.13  christos 	size_t mlen = sshbuf_len(m);
    175  1.13  christos 	int r;
    176   1.1      adam 
    177  1.18  christos 	if (fd == -1)
    178  1.18  christos 		return;
    179  1.13  christos 	POKE_U32(buf, mlen);
    180   1.1      adam 	if (atomicio(vwrite, fd, buf, 4) != 4 ||
    181  1.13  christos 	    atomicio(vwrite, fd, sshbuf_mutable_ptr(m),
    182  1.13  christos 	    sshbuf_len(m)) != sshbuf_len(m))
    183   1.1      adam 		error("write to helper failed");
    184  1.13  christos 	if ((r = sshbuf_consume(m, mlen)) != 0)
    185  1.17  christos 		fatal_fr(r, "consume");
    186   1.1      adam }
    187   1.1      adam 
    188   1.1      adam static int
    189  1.18  christos recv_msg(int fd, struct sshbuf *m)
    190   1.1      adam {
    191   1.1      adam 	u_int l, len;
    192  1.13  christos 	u_char c, buf[1024];
    193  1.13  christos 	int r;
    194   1.1      adam 
    195  1.18  christos 	sshbuf_reset(m);
    196  1.18  christos 	if (fd == -1)
    197  1.18  christos 		return 0; /* XXX */
    198   1.1      adam 	if ((len = atomicio(read, fd, buf, 4)) != 4) {
    199   1.1      adam 		error("read from helper failed: %u", len);
    200   1.1      adam 		return (0); /* XXX */
    201   1.1      adam 	}
    202  1.13  christos 	len = PEEK_U32(buf);
    203   1.1      adam 	if (len > 256 * 1024)
    204   1.1      adam 		fatal("response too long: %u", len);
    205   1.1      adam 	/* read len bytes into m */
    206   1.1      adam 	while (len > 0) {
    207   1.1      adam 		l = len;
    208   1.1      adam 		if (l > sizeof(buf))
    209   1.1      adam 			l = sizeof(buf);
    210   1.1      adam 		if (atomicio(read, fd, buf, l) != l) {
    211   1.1      adam 			error("response from helper failed.");
    212   1.1      adam 			return (0); /* XXX */
    213   1.1      adam 		}
    214  1.13  christos 		if ((r = sshbuf_put(m, buf, l)) != 0)
    215  1.17  christos 			fatal_fr(r, "sshbuf_put");
    216   1.1      adam 		len -= l;
    217   1.1      adam 	}
    218  1.13  christos 	if ((r = sshbuf_get_u8(m, &c)) != 0)
    219  1.17  christos 		fatal_fr(r, "parse type");
    220  1.13  christos 	return c;
    221   1.1      adam }
    222   1.1      adam 
    223   1.1      adam int
    224   1.1      adam pkcs11_init(int interactive)
    225   1.1      adam {
    226  1.18  christos 	return 0;
    227   1.1      adam }
    228   1.1      adam 
    229   1.1      adam void
    230   1.1      adam pkcs11_terminate(void)
    231   1.1      adam {
    232  1.18  christos 	size_t i;
    233  1.18  christos 
    234  1.18  christos 	debug3_f("terminating %zu helpers", nhelpers);
    235  1.18  christos 	for (i = 0; i < nhelpers; i++)
    236  1.18  christos 		helper_terminate(helpers[i]);
    237   1.1      adam }
    238   1.1      adam 
    239   1.1      adam static int
    240  1.15  christos rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
    241   1.1      adam {
    242  1.15  christos 	struct sshkey *key = NULL;
    243  1.15  christos 	struct sshbuf *msg = NULL;
    244  1.15  christos 	u_char *blob = NULL, *signature = NULL;
    245  1.13  christos 	size_t blen, slen = 0;
    246  1.13  christos 	int r, ret = -1;
    247  1.18  christos 	struct helper *helper;
    248   1.1      adam 
    249  1.18  christos 	if ((helper = helper_by_rsa(rsa)) == NULL || helper->fd == -1)
    250  1.18  christos 		fatal_f("no helper for PKCS11 key");
    251  1.18  christos 	debug3_f("signing with PKCS11 provider %s", helper->path);
    252   1.1      adam 	if (padding != RSA_PKCS1_PADDING)
    253  1.15  christos 		goto fail;
    254  1.20  christos 	if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
    255  1.17  christos 		error_f("sshkey_new failed");
    256  1.15  christos 		goto fail;
    257  1.15  christos 	}
    258  1.20  christos 	if ((key->pkey = EVP_PKEY_new()) == NULL ||
    259  1.20  christos 	   EVP_PKEY_set1_RSA(key->pkey, rsa) != 1) {
    260  1.20  christos 		error_f("pkey setup failed");
    261  1.20  christos 		goto fail;
    262  1.20  christos 	}
    263  1.20  christos 
    264  1.15  christos 	key->type = KEY_RSA;
    265  1.15  christos 	if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
    266  1.17  christos 		error_fr(r, "encode key");
    267  1.15  christos 		goto fail;
    268  1.13  christos 	}
    269  1.13  christos 	if ((msg = sshbuf_new()) == NULL)
    270  1.17  christos 		fatal_f("sshbuf_new failed");
    271  1.13  christos 	if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
    272  1.13  christos 	    (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
    273  1.13  christos 	    (r = sshbuf_put_string(msg, from, flen)) != 0 ||
    274  1.13  christos 	    (r = sshbuf_put_u32(msg, 0)) != 0)
    275  1.17  christos 		fatal_fr(r, "compose");
    276  1.18  christos 	send_msg(helper->fd, msg);
    277  1.13  christos 	sshbuf_reset(msg);
    278   1.1      adam 
    279  1.18  christos 	if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) {
    280  1.13  christos 		if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
    281  1.17  christos 			fatal_fr(r, "parse");
    282  1.13  christos 		if (slen <= (size_t)RSA_size(rsa)) {
    283   1.1      adam 			memcpy(to, signature, slen);
    284   1.1      adam 			ret = slen;
    285   1.1      adam 		}
    286   1.4  christos 		free(signature);
    287   1.1      adam 	}
    288  1.15  christos  fail:
    289  1.15  christos 	free(blob);
    290  1.15  christos 	sshkey_free(key);
    291  1.13  christos 	sshbuf_free(msg);
    292   1.1      adam 	return (ret);
    293   1.1      adam }
    294   1.1      adam 
    295  1.18  christos static int
    296  1.18  christos rsa_finish(RSA *rsa)
    297  1.18  christos {
    298  1.18  christos 	struct helper *helper;
    299  1.18  christos 
    300  1.18  christos 	if ((helper = helper_by_rsa(rsa)) == NULL)
    301  1.18  christos 		fatal_f("no helper for PKCS11 key");
    302  1.18  christos 	debug3_f("free PKCS11 RSA key for provider %s", helper->path);
    303  1.18  christos 	if (helper->rsa_finish != NULL)
    304  1.18  christos 		helper->rsa_finish(rsa);
    305  1.18  christos 	if (helper->nrsa == 0)
    306  1.18  christos 		fatal_f("RSA refcount error");
    307  1.18  christos 	helper->nrsa--;
    308  1.18  christos 	debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
    309  1.18  christos 	    helper->path, helper->nrsa, helper->nec);
    310  1.18  christos 	if (helper->nrsa == 0 && helper->nec == 0)
    311  1.18  christos 		helper_terminate(helper);
    312  1.18  christos 	return 1;
    313  1.18  christos }
    314  1.18  christos 
    315  1.15  christos static ECDSA_SIG *
    316  1.15  christos ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
    317  1.15  christos     const BIGNUM *rp, EC_KEY *ec)
    318  1.15  christos {
    319  1.15  christos 	struct sshkey *key = NULL;
    320  1.15  christos 	struct sshbuf *msg = NULL;
    321  1.15  christos 	ECDSA_SIG *ret = NULL;
    322  1.15  christos 	const u_char *cp;
    323  1.15  christos 	u_char *blob = NULL, *signature = NULL;
    324  1.15  christos 	size_t blen, slen = 0;
    325  1.15  christos 	int r, nid;
    326  1.18  christos 	struct helper *helper;
    327  1.15  christos 
    328  1.18  christos 	if ((helper = helper_by_ec(ec)) == NULL || helper->fd == -1)
    329  1.18  christos 		fatal_f("no helper for PKCS11 key");
    330  1.18  christos 	debug3_f("signing with PKCS11 provider %s", helper->path);
    331  1.20  christos 
    332  1.20  christos 	if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
    333  1.20  christos 		error_f("sshkey_new failed");
    334  1.15  christos 		goto fail;
    335  1.15  christos 	}
    336  1.20  christos 	if ((key->pkey = EVP_PKEY_new()) == NULL ||
    337  1.20  christos 	    EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1) {
    338  1.20  christos 		error("pkey setup failed");
    339  1.20  christos 		goto fail;
    340  1.20  christos 	}
    341  1.20  christos 	if ((nid = sshkey_ecdsa_pkey_to_nid(key->pkey)) < 0) {
    342  1.20  christos 		error("couldn't get curve nid");
    343  1.15  christos 		goto fail;
    344  1.15  christos 	}
    345  1.15  christos 	key->ecdsa_nid = nid;
    346  1.15  christos 	key->type = KEY_ECDSA;
    347  1.15  christos 
    348  1.15  christos 	if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
    349  1.17  christos 		error_fr(r, "encode key");
    350  1.15  christos 		goto fail;
    351  1.15  christos 	}
    352  1.15  christos 	if ((msg = sshbuf_new()) == NULL)
    353  1.17  christos 		fatal_f("sshbuf_new failed");
    354  1.15  christos 	if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
    355  1.15  christos 	    (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
    356  1.15  christos 	    (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 ||
    357  1.15  christos 	    (r = sshbuf_put_u32(msg, 0)) != 0)
    358  1.17  christos 		fatal_fr(r, "compose");
    359  1.18  christos 	send_msg(helper->fd, msg);
    360  1.15  christos 	sshbuf_reset(msg);
    361  1.15  christos 
    362  1.18  christos 	if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) {
    363  1.15  christos 		if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
    364  1.17  christos 			fatal_fr(r, "parse");
    365  1.15  christos 		cp = signature;
    366  1.15  christos 		ret = d2i_ECDSA_SIG(NULL, &cp, slen);
    367  1.15  christos 		free(signature);
    368  1.15  christos 	}
    369  1.15  christos 
    370  1.15  christos  fail:
    371  1.15  christos 	free(blob);
    372  1.15  christos 	sshkey_free(key);
    373  1.15  christos 	sshbuf_free(msg);
    374  1.15  christos 	return (ret);
    375  1.15  christos }
    376  1.15  christos 
    377  1.18  christos static void
    378  1.18  christos ecdsa_do_finish(EC_KEY *ec)
    379  1.18  christos {
    380  1.18  christos 	struct helper *helper;
    381  1.18  christos 
    382  1.18  christos 	if ((helper = helper_by_ec(ec)) == NULL)
    383  1.18  christos 		fatal_f("no helper for PKCS11 key");
    384  1.18  christos 	debug3_f("free PKCS11 ECDSA key for provider %s", helper->path);
    385  1.18  christos 	if (helper->ec_finish != NULL)
    386  1.18  christos 		helper->ec_finish(ec);
    387  1.18  christos 	if (helper->nec == 0)
    388  1.18  christos 		fatal_f("ECDSA refcount error");
    389  1.18  christos 	helper->nec--;
    390  1.18  christos 	debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
    391  1.18  christos 	    helper->path, helper->nrsa, helper->nec);
    392  1.18  christos 	if (helper->nrsa == 0 && helper->nec == 0)
    393  1.18  christos 		helper_terminate(helper);
    394  1.18  christos }
    395  1.15  christos 
    396  1.15  christos /* redirect private key crypto operations to the ssh-pkcs11-helper */
    397  1.15  christos static void
    398  1.18  christos wrap_key(struct helper *helper, struct sshkey *k)
    399  1.15  christos {
    400  1.20  christos 	RSA *rsa = NULL;
    401  1.20  christos 	EC_KEY *ecdsa = NULL;
    402  1.20  christos 
    403  1.18  christos 	debug3_f("wrap %s for provider %s", sshkey_type(k), helper->path);
    404  1.18  christos 	if (k->type == KEY_RSA) {
    405  1.20  christos 		if ((rsa = EVP_PKEY_get1_RSA(k->pkey)) == NULL)
    406  1.20  christos 			fatal_f("no RSA key");
    407  1.20  christos 		if (RSA_set_method(rsa, helper->rsa_meth) != 1)
    408  1.20  christos 			fatal_f("RSA_set_method failed");
    409  1.18  christos 		if (helper->nrsa++ >= INT_MAX)
    410  1.18  christos 			fatal_f("RSA refcount error");
    411  1.20  christos 		if (EVP_PKEY_set1_RSA(k->pkey, rsa) != 1)
    412  1.20  christos 			fatal_f("EVP_PKEY_set1_RSA failed");
    413  1.20  christos 		RSA_free(rsa);
    414  1.18  christos 	} else if (k->type == KEY_ECDSA) {
    415  1.20  christos 		if ((ecdsa = EVP_PKEY_get1_EC_KEY(k->pkey)) == NULL)
    416  1.20  christos 			fatal_f("no ECDSA key");
    417  1.20  christos 		if (EC_KEY_set_method(ecdsa, helper->ec_meth) != 1)
    418  1.20  christos 			fatal_f("EC_KEY_set_method failed");
    419  1.18  christos 		if (helper->nec++ >= INT_MAX)
    420  1.18  christos 			fatal_f("EC refcount error");
    421  1.20  christos 		if (EVP_PKEY_set1_EC_KEY(k->pkey, ecdsa) != 1)
    422  1.20  christos 			fatal_f("EVP_PKEY_set1_EC_KEY failed");
    423  1.20  christos 		EC_KEY_free(ecdsa);
    424  1.18  christos 	} else
    425  1.17  christos 		fatal_f("unknown key type");
    426  1.18  christos 	k->flags |= SSHKEY_FLAG_EXT;
    427  1.18  christos 	debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
    428  1.18  christos 	    helper->path, helper->nrsa, helper->nec);
    429  1.15  christos }
    430  1.15  christos 
    431  1.19  christos /*
    432  1.19  christos  * Make a private PKCS#11-backed certificate by grafting a previously-loaded
    433  1.19  christos  * PKCS#11 private key and a public certificate key.
    434  1.19  christos  */
    435  1.19  christos int
    436  1.19  christos pkcs11_make_cert(const struct sshkey *priv,
    437  1.19  christos     const struct sshkey *certpub, struct sshkey **certprivp)
    438  1.19  christos {
    439  1.19  christos 	struct helper *helper = NULL;
    440  1.19  christos 	struct sshkey *ret;
    441  1.19  christos 	int r;
    442  1.20  christos 	RSA *rsa_priv = NULL, *rsa_cert = NULL;
    443  1.20  christos 	EC_KEY *ec_priv = NULL, *ec_cert = NULL;
    444  1.19  christos 
    445  1.19  christos 	debug3_f("private key type %s cert type %s", sshkey_type(priv),
    446  1.19  christos 	    sshkey_type(certpub));
    447  1.19  christos 	*certprivp = NULL;
    448  1.19  christos 	if (!sshkey_is_cert(certpub) || sshkey_is_cert(priv) ||
    449  1.19  christos 	    !sshkey_equal_public(priv, certpub)) {
    450  1.19  christos 		error_f("private key %s doesn't match cert %s",
    451  1.19  christos 		    sshkey_type(priv), sshkey_type(certpub));
    452  1.19  christos 		return SSH_ERR_INVALID_ARGUMENT;
    453  1.19  christos 	}
    454  1.19  christos 	*certprivp = NULL;
    455  1.19  christos 	if (priv->type == KEY_RSA) {
    456  1.20  christos 		if ((rsa_priv = EVP_PKEY_get1_RSA(priv->pkey)) == NULL)
    457  1.20  christos 			fatal_f("no RSA pkey");
    458  1.20  christos 		if ((helper = helper_by_rsa(rsa_priv)) == NULL ||
    459  1.19  christos 		    helper->fd == -1)
    460  1.19  christos 			fatal_f("no helper for PKCS11 RSA key");
    461  1.19  christos 		if ((r = sshkey_from_private(priv, &ret)) != 0)
    462  1.19  christos 			fatal_fr(r, "copy key");
    463  1.20  christos 		if ((rsa_cert = EVP_PKEY_get1_RSA(ret->pkey)) == NULL)
    464  1.20  christos 			fatal_f("no RSA cert pkey");
    465  1.20  christos 		if (RSA_set_method(rsa_cert, helper->rsa_meth) != 1)
    466  1.20  christos 			fatal_f("RSA_set_method failed");
    467  1.19  christos 		if (helper->nrsa++ >= INT_MAX)
    468  1.19  christos 			fatal_f("RSA refcount error");
    469  1.20  christos 		if (EVP_PKEY_set1_RSA(ret->pkey, rsa_cert) != 1)
    470  1.20  christos 			fatal_f("EVP_PKEY_set1_RSA failed");
    471  1.20  christos 		RSA_free(rsa_priv);
    472  1.20  christos 		RSA_free(rsa_cert);
    473  1.19  christos 	} else if (priv->type == KEY_ECDSA) {
    474  1.20  christos 		if ((ec_priv = EVP_PKEY_get1_EC_KEY(priv->pkey)) == NULL)
    475  1.20  christos 			fatal_f("no EC pkey");
    476  1.20  christos 		if ((helper = helper_by_ec(ec_priv)) == NULL ||
    477  1.19  christos 		    helper->fd == -1)
    478  1.19  christos 			fatal_f("no helper for PKCS11 EC key");
    479  1.19  christos 		if ((r = sshkey_from_private(priv, &ret)) != 0)
    480  1.19  christos 			fatal_fr(r, "copy key");
    481  1.20  christos 		if ((ec_cert = EVP_PKEY_get1_EC_KEY(ret->pkey)) == NULL)
    482  1.20  christos 			fatal_f("no EC cert pkey");
    483  1.20  christos 		if (EC_KEY_set_method(ec_cert, helper->ec_meth) != 1)
    484  1.20  christos 			fatal_f("EC_KEY_set_method failed");
    485  1.19  christos 		if (helper->nec++ >= INT_MAX)
    486  1.19  christos 			fatal_f("EC refcount error");
    487  1.20  christos 		if (EVP_PKEY_set1_EC_KEY(ret->pkey, ec_cert) != 1)
    488  1.20  christos 			fatal_f("EVP_PKEY_set1_EC_KEY failed");
    489  1.20  christos 		EC_KEY_free(ec_priv);
    490  1.20  christos 		EC_KEY_free(ec_cert);
    491  1.19  christos 	} else
    492  1.19  christos 		fatal_f("unknown key type %s", sshkey_type(priv));
    493  1.19  christos 
    494  1.19  christos 	ret->flags |= SSHKEY_FLAG_EXT;
    495  1.19  christos 	if ((r = sshkey_to_certified(ret)) != 0 ||
    496  1.19  christos 	    (r = sshkey_cert_copy(certpub, ret)) != 0)
    497  1.19  christos 		fatal_fr(r, "graft certificate");
    498  1.19  christos 	debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
    499  1.19  christos 	    helper->path, helper->nrsa, helper->nec);
    500  1.19  christos 	/* success */
    501  1.19  christos 	*certprivp = ret;
    502  1.19  christos 	return 0;
    503  1.19  christos }
    504  1.19  christos 
    505   1.1      adam static int
    506  1.18  christos pkcs11_start_helper_methods(struct helper *helper)
    507   1.1      adam {
    508  1.18  christos 	int (*ec_init)(EC_KEY *key);
    509  1.18  christos 	int (*ec_copy)(EC_KEY *dest, const EC_KEY *src);
    510  1.18  christos 	int (*ec_set_group)(EC_KEY *key, const EC_GROUP *grp);
    511  1.18  christos 	int (*ec_set_private)(EC_KEY *key, const BIGNUM *priv_key);
    512  1.18  christos 	int (*ec_set_public)(EC_KEY *key, const EC_POINT *pub_key);
    513  1.18  christos 	int (*ec_sign)(int, const unsigned char *, int, unsigned char *,
    514  1.18  christos 	    unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
    515  1.18  christos 	RSA_METHOD *rsa_meth;
    516  1.18  christos 	EC_KEY_METHOD *ec_meth;
    517  1.15  christos 
    518  1.18  christos 	if ((ec_meth = EC_KEY_METHOD_new(EC_KEY_OpenSSL())) == NULL)
    519  1.18  christos 		return -1;
    520  1.18  christos 	EC_KEY_METHOD_get_sign(ec_meth, &ec_sign, NULL, NULL);
    521  1.18  christos 	EC_KEY_METHOD_set_sign(ec_meth, ec_sign, NULL, ecdsa_do_sign);
    522  1.18  christos 	EC_KEY_METHOD_get_init(ec_meth, &ec_init, &helper->ec_finish,
    523  1.18  christos 	    &ec_copy, &ec_set_group, &ec_set_private, &ec_set_public);
    524  1.18  christos 	EC_KEY_METHOD_set_init(ec_meth, ec_init, ecdsa_do_finish,
    525  1.18  christos 	    ec_copy, ec_set_group, ec_set_private, ec_set_public);
    526   1.1      adam 
    527  1.18  christos 	if ((rsa_meth = RSA_meth_dup(RSA_get_default_method())) == NULL)
    528  1.17  christos 		fatal_f("RSA_meth_dup failed");
    529  1.18  christos 	helper->rsa_finish = RSA_meth_get_finish(rsa_meth);
    530  1.18  christos 	if (!RSA_meth_set1_name(rsa_meth, "ssh-pkcs11-helper") ||
    531  1.18  christos 	    !RSA_meth_set_priv_enc(rsa_meth, rsa_encrypt) ||
    532  1.18  christos 	    !RSA_meth_set_finish(rsa_meth, rsa_finish))
    533  1.17  christos 		fatal_f("failed to prepare method");
    534  1.15  christos 
    535  1.18  christos 	helper->ec_meth = ec_meth;
    536  1.18  christos 	helper->rsa_meth = rsa_meth;
    537  1.18  christos 	return 0;
    538   1.1      adam }
    539   1.1      adam 
    540  1.18  christos static struct helper *
    541  1.18  christos pkcs11_start_helper(const char *path)
    542   1.1      adam {
    543   1.1      adam 	int pair[2];
    544  1.18  christos 	const char *prog, *verbosity = NULL;
    545  1.18  christos 	struct helper *helper;
    546  1.18  christos 	pid_t pid;
    547  1.18  christos 
    548  1.18  christos 	if (nhelpers >= INT_MAX)
    549  1.18  christos 		fatal_f("too many helpers");
    550  1.18  christos 	debug3_f("start helper for %s", path);
    551  1.18  christos 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
    552  1.18  christos 		error_f("socketpair: %s", strerror(errno));
    553  1.18  christos 		return NULL;
    554  1.15  christos 	}
    555  1.18  christos 	helper = xcalloc(1, sizeof(*helper));
    556  1.18  christos 	if (pkcs11_start_helper_methods(helper) == -1) {
    557  1.18  christos 		error_f("pkcs11_start_helper_methods failed");
    558  1.18  christos 		goto fail;
    559   1.1      adam 	}
    560   1.1      adam 	if ((pid = fork()) == -1) {
    561  1.18  christos 		error_f("fork: %s", strerror(errno));
    562  1.18  christos  fail:
    563  1.18  christos 		close(pair[0]);
    564  1.18  christos 		close(pair[1]);
    565  1.18  christos 		RSA_meth_free(helper->rsa_meth);
    566  1.18  christos 		EC_KEY_METHOD_free(helper->ec_meth);
    567  1.18  christos 		free(helper);
    568  1.18  christos 		return NULL;
    569   1.1      adam 	} else if (pid == 0) {
    570   1.1      adam 		if ((dup2(pair[1], STDIN_FILENO) == -1) ||
    571   1.1      adam 		    (dup2(pair[1], STDOUT_FILENO) == -1)) {
    572   1.1      adam 			fprintf(stderr, "dup2: %s\n", strerror(errno));
    573   1.1      adam 			_exit(1);
    574   1.1      adam 		}
    575   1.1      adam 		close(pair[0]);
    576   1.1      adam 		close(pair[1]);
    577  1.18  christos 		prog = getenv("SSH_PKCS11_HELPER");
    578  1.18  christos 		if (prog == NULL || strlen(prog) == 0)
    579  1.18  christos 			prog = _PATH_SSH_PKCS11_HELPER;
    580  1.18  christos 		if (log_level_get() >= SYSLOG_LEVEL_DEBUG1)
    581  1.18  christos 			verbosity = "-vvv";
    582  1.18  christos 		debug_f("starting %s %s", prog,
    583  1.15  christos 		    verbosity == NULL ? "" : verbosity);
    584  1.18  christos 		execlp(prog, prog, verbosity, (char *)NULL);
    585  1.18  christos 		fprintf(stderr, "exec: %s: %s\n", prog, strerror(errno));
    586   1.1      adam 		_exit(1);
    587   1.1      adam 	}
    588   1.1      adam 	close(pair[1]);
    589  1.18  christos 	helper->fd = pair[0];
    590  1.18  christos 	helper->path = xstrdup(path);
    591  1.18  christos 	helper->pid = pid;
    592  1.18  christos 	debug3_f("helper %zu for \"%s\" on fd %d pid %ld", nhelpers,
    593  1.18  christos 	    helper->path, helper->fd, (long)helper->pid);
    594  1.18  christos 	helpers = xrecallocarray(helpers, nhelpers,
    595  1.18  christos 	    nhelpers + 1, sizeof(*helpers));
    596  1.18  christos 	helpers[nhelpers++] = helper;
    597  1.18  christos 	return helper;
    598   1.1      adam }
    599   1.1      adam 
    600   1.1      adam int
    601  1.16  christos pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp,
    602  1.16  christos     char ***labelsp)
    603   1.1      adam {
    604  1.10  christos 	struct sshkey *k;
    605  1.15  christos 	int r, type;
    606   1.1      adam 	u_char *blob;
    607  1.16  christos 	char *label;
    608  1.13  christos 	size_t blen;
    609  1.13  christos 	u_int nkeys, i;
    610  1.13  christos 	struct sshbuf *msg;
    611  1.18  christos 	struct helper *helper;
    612   1.1      adam 
    613  1.18  christos 	if ((helper = helper_by_provider(name)) == NULL &&
    614  1.18  christos 	    (helper = pkcs11_start_helper(name)) == NULL)
    615  1.18  christos 		return -1;
    616   1.1      adam 
    617  1.13  christos 	if ((msg = sshbuf_new()) == NULL)
    618  1.17  christos 		fatal_f("sshbuf_new failed");
    619  1.13  christos 	if ((r = sshbuf_put_u8(msg, SSH_AGENTC_ADD_SMARTCARD_KEY)) != 0 ||
    620  1.13  christos 	    (r = sshbuf_put_cstring(msg, name)) != 0 ||
    621  1.13  christos 	    (r = sshbuf_put_cstring(msg, pin)) != 0)
    622  1.17  christos 		fatal_fr(r, "compose");
    623  1.18  christos 	send_msg(helper->fd, msg);
    624  1.13  christos 	sshbuf_reset(msg);
    625  1.13  christos 
    626  1.18  christos 	type = recv_msg(helper->fd, msg);
    627  1.15  christos 	if (type == SSH2_AGENT_IDENTITIES_ANSWER) {
    628  1.13  christos 		if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
    629  1.17  christos 			fatal_fr(r, "parse nkeys");
    630  1.13  christos 		*keysp = xcalloc(nkeys, sizeof(struct sshkey *));
    631  1.16  christos 		if (labelsp)
    632  1.16  christos 			*labelsp = xcalloc(nkeys, sizeof(char *));
    633   1.1      adam 		for (i = 0; i < nkeys; i++) {
    634  1.13  christos 			/* XXX clean up properly instead of fatal() */
    635  1.13  christos 			if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
    636  1.16  christos 			    (r = sshbuf_get_cstring(msg, &label, NULL)) != 0)
    637  1.17  christos 				fatal_fr(r, "parse key");
    638  1.13  christos 			if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
    639  1.17  christos 				fatal_fr(r, "decode key");
    640  1.18  christos 			wrap_key(helper, k);
    641   1.1      adam 			(*keysp)[i] = k;
    642  1.16  christos 			if (labelsp)
    643  1.16  christos 				(*labelsp)[i] = label;
    644  1.16  christos 			else
    645  1.16  christos 				free(label);
    646   1.4  christos 			free(blob);
    647   1.1      adam 		}
    648  1.15  christos 	} else if (type == SSH2_AGENT_FAILURE) {
    649  1.15  christos 		if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
    650  1.15  christos 			nkeys = -1;
    651   1.1      adam 	} else {
    652   1.1      adam 		nkeys = -1;
    653   1.1      adam 	}
    654  1.13  christos 	sshbuf_free(msg);
    655   1.1      adam 	return (nkeys);
    656   1.1      adam }
    657   1.1      adam 
    658   1.1      adam int
    659   1.1      adam pkcs11_del_provider(char *name)
    660   1.1      adam {
    661  1.18  christos 	struct helper *helper;
    662   1.1      adam 
    663  1.18  christos 	/*
    664  1.18  christos 	 * ssh-agent deletes keys before calling this, so the helper entry
    665  1.18  christos 	 * should be gone before we get here.
    666  1.18  christos 	 */
    667  1.18  christos 	debug3_f("delete %s", name);
    668  1.18  christos 	if ((helper = helper_by_provider(name)) != NULL)
    669  1.18  christos 		helper_terminate(helper);
    670  1.18  christos 	return 0;
    671   1.1      adam }
    672