xref: /openssh-portable/ssh-pkcs11-client.c (revision 816036f1)
1*816036f1Sdjm@openbsd.org /* $OpenBSD: ssh-pkcs11-client.c,v 1.17 2020/10/18 11:32:02 djm Exp $ */
27ea845e4SDamien Miller /*
37ea845e4SDamien Miller  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
493f02107Sdjm@openbsd.org  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
57ea845e4SDamien Miller  *
67ea845e4SDamien Miller  * Permission to use, copy, modify, and distribute this software for any
77ea845e4SDamien Miller  * purpose with or without fee is hereby granted, provided that the above
87ea845e4SDamien Miller  * copyright notice and this permission notice appear in all copies.
97ea845e4SDamien Miller  *
107ea845e4SDamien Miller  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
117ea845e4SDamien Miller  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
127ea845e4SDamien Miller  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
137ea845e4SDamien Miller  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
147ea845e4SDamien Miller  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
157ea845e4SDamien Miller  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
167ea845e4SDamien Miller  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177ea845e4SDamien Miller  */
187ea845e4SDamien Miller 
198ad0fbd9SDamien Miller #include "includes.h"
208ad0fbd9SDamien Miller 
21dfa4156dSDamien Miller #ifdef ENABLE_PKCS11
22dfa4156dSDamien Miller 
237ea845e4SDamien Miller #include <sys/types.h>
248ad0fbd9SDamien Miller #ifdef HAVE_SYS_TIME_H
257ea845e4SDamien Miller # include <sys/time.h>
268ad0fbd9SDamien Miller #endif
277ea845e4SDamien Miller #include <sys/socket.h>
287ea845e4SDamien Miller 
297ea845e4SDamien Miller #include <stdarg.h>
307ea845e4SDamien Miller #include <string.h>
317ea845e4SDamien Miller #include <unistd.h>
327ea845e4SDamien Miller #include <errno.h>
337ea845e4SDamien Miller 
3493f02107Sdjm@openbsd.org #include <openssl/ecdsa.h>
358668706dSDamien Miller #include <openssl/rsa.h>
368668706dSDamien Miller 
3748f54b9dSDamien Miller #include "openbsd-compat/openssl-compat.h"
3848f54b9dSDamien Miller 
397ea845e4SDamien Miller #include "pathnames.h"
407ea845e4SDamien Miller #include "xmalloc.h"
41ff55f4adSmarkus@openbsd.org #include "sshbuf.h"
427ea845e4SDamien Miller #include "log.h"
437ea845e4SDamien Miller #include "misc.h"
44ff55f4adSmarkus@openbsd.org #include "sshkey.h"
457ea845e4SDamien Miller #include "authfd.h"
467ea845e4SDamien Miller #include "atomicio.h"
477ea845e4SDamien Miller #include "ssh-pkcs11.h"
48ff55f4adSmarkus@openbsd.org #include "ssherr.h"
497ea845e4SDamien Miller 
507ea845e4SDamien Miller /* borrows code from sftp-server and ssh-agent */
517ea845e4SDamien Miller 
52c7670b09Sdjm@openbsd.org static int fd = -1;
53c7670b09Sdjm@openbsd.org static pid_t pid = -1;
547ea845e4SDamien Miller 
557ea845e4SDamien Miller static void
send_msg(struct sshbuf * m)56ff55f4adSmarkus@openbsd.org send_msg(struct sshbuf *m)
577ea845e4SDamien Miller {
587ea845e4SDamien Miller 	u_char buf[4];
59ff55f4adSmarkus@openbsd.org 	size_t mlen = sshbuf_len(m);
60ff55f4adSmarkus@openbsd.org 	int r;
617ea845e4SDamien Miller 
62ff55f4adSmarkus@openbsd.org 	POKE_U32(buf, mlen);
637ea845e4SDamien Miller 	if (atomicio(vwrite, fd, buf, 4) != 4 ||
6449f47e65Smarkus@openbsd.org 	    atomicio(vwrite, fd, sshbuf_mutable_ptr(m),
65ff55f4adSmarkus@openbsd.org 	    sshbuf_len(m)) != sshbuf_len(m))
667ea845e4SDamien Miller 		error("write to helper failed");
67ff55f4adSmarkus@openbsd.org 	if ((r = sshbuf_consume(m, mlen)) != 0)
68*816036f1Sdjm@openbsd.org 		fatal_fr(r, "consume");
697ea845e4SDamien Miller }
707ea845e4SDamien Miller 
717ea845e4SDamien Miller static int
recv_msg(struct sshbuf * m)72ff55f4adSmarkus@openbsd.org recv_msg(struct sshbuf *m)
737ea845e4SDamien Miller {
747ea845e4SDamien Miller 	u_int l, len;
75ff55f4adSmarkus@openbsd.org 	u_char c, buf[1024];
76ff55f4adSmarkus@openbsd.org 	int r;
777ea845e4SDamien Miller 
787ea845e4SDamien Miller 	if ((len = atomicio(read, fd, buf, 4)) != 4) {
797ea845e4SDamien Miller 		error("read from helper failed: %u", len);
807ea845e4SDamien Miller 		return (0); /* XXX */
817ea845e4SDamien Miller 	}
82ff55f4adSmarkus@openbsd.org 	len = PEEK_U32(buf);
837ea845e4SDamien Miller 	if (len > 256 * 1024)
847ea845e4SDamien Miller 		fatal("response too long: %u", len);
857ea845e4SDamien Miller 	/* read len bytes into m */
86ff55f4adSmarkus@openbsd.org 	sshbuf_reset(m);
877ea845e4SDamien Miller 	while (len > 0) {
887ea845e4SDamien Miller 		l = len;
897ea845e4SDamien Miller 		if (l > sizeof(buf))
907ea845e4SDamien Miller 			l = sizeof(buf);
917ea845e4SDamien Miller 		if (atomicio(read, fd, buf, l) != l) {
927ea845e4SDamien Miller 			error("response from helper failed.");
937ea845e4SDamien Miller 			return (0); /* XXX */
947ea845e4SDamien Miller 		}
95ff55f4adSmarkus@openbsd.org 		if ((r = sshbuf_put(m, buf, l)) != 0)
96*816036f1Sdjm@openbsd.org 			fatal_fr(r, "sshbuf_put");
977ea845e4SDamien Miller 		len -= l;
987ea845e4SDamien Miller 	}
99ff55f4adSmarkus@openbsd.org 	if ((r = sshbuf_get_u8(m, &c)) != 0)
100*816036f1Sdjm@openbsd.org 		fatal_fr(r, "parse type");
101ff55f4adSmarkus@openbsd.org 	return c;
1027ea845e4SDamien Miller }
1037ea845e4SDamien Miller 
1047ea845e4SDamien Miller int
pkcs11_init(int interactive)1057ea845e4SDamien Miller pkcs11_init(int interactive)
1067ea845e4SDamien Miller {
1077ea845e4SDamien Miller 	return (0);
1087ea845e4SDamien Miller }
1097ea845e4SDamien Miller 
1107ea845e4SDamien Miller void
pkcs11_terminate(void)1117ea845e4SDamien Miller pkcs11_terminate(void)
1127ea845e4SDamien Miller {
11334843801Stb@openbsd.org 	if (fd >= 0)
1147ea845e4SDamien Miller 		close(fd);
1157ea845e4SDamien Miller }
1167ea845e4SDamien Miller 
1177ea845e4SDamien Miller static int
rsa_encrypt(int flen,const u_char * from,u_char * to,RSA * rsa,int padding)11893f02107Sdjm@openbsd.org rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
1197ea845e4SDamien Miller {
1200c50992aSdjm@openbsd.org 	struct sshkey *key = NULL;
1210c50992aSdjm@openbsd.org 	struct sshbuf *msg = NULL;
1220c50992aSdjm@openbsd.org 	u_char *blob = NULL, *signature = NULL;
123ff55f4adSmarkus@openbsd.org 	size_t blen, slen = 0;
124ff55f4adSmarkus@openbsd.org 	int r, ret = -1;
1257ea845e4SDamien Miller 
1267ea845e4SDamien Miller 	if (padding != RSA_PKCS1_PADDING)
1270c50992aSdjm@openbsd.org 		goto fail;
1280c50992aSdjm@openbsd.org 	key = sshkey_new(KEY_UNSPEC);
1290c50992aSdjm@openbsd.org 	if (key == NULL) {
130*816036f1Sdjm@openbsd.org 		error_f("sshkey_new failed");
1310c50992aSdjm@openbsd.org 		goto fail;
1320c50992aSdjm@openbsd.org 	}
1330c50992aSdjm@openbsd.org 	key->type = KEY_RSA;
1340c50992aSdjm@openbsd.org 	RSA_up_ref(rsa);
1350c50992aSdjm@openbsd.org 	key->rsa = rsa;
1360c50992aSdjm@openbsd.org 	if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
137*816036f1Sdjm@openbsd.org 		error_fr(r, "encode key");
1380c50992aSdjm@openbsd.org 		goto fail;
139ff55f4adSmarkus@openbsd.org 	}
140ff55f4adSmarkus@openbsd.org 	if ((msg = sshbuf_new()) == NULL)
141*816036f1Sdjm@openbsd.org 		fatal_f("sshbuf_new failed");
142ff55f4adSmarkus@openbsd.org 	if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
143ff55f4adSmarkus@openbsd.org 	    (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
144ff55f4adSmarkus@openbsd.org 	    (r = sshbuf_put_string(msg, from, flen)) != 0 ||
145ff55f4adSmarkus@openbsd.org 	    (r = sshbuf_put_u32(msg, 0)) != 0)
146*816036f1Sdjm@openbsd.org 		fatal_fr(r, "compose");
147ff55f4adSmarkus@openbsd.org 	send_msg(msg);
148ff55f4adSmarkus@openbsd.org 	sshbuf_reset(msg);
1497ea845e4SDamien Miller 
150ff55f4adSmarkus@openbsd.org 	if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) {
151ff55f4adSmarkus@openbsd.org 		if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
152*816036f1Sdjm@openbsd.org 			fatal_fr(r, "parse");
153ff55f4adSmarkus@openbsd.org 		if (slen <= (size_t)RSA_size(rsa)) {
1547ea845e4SDamien Miller 			memcpy(to, signature, slen);
1557ea845e4SDamien Miller 			ret = slen;
1567ea845e4SDamien Miller 		}
157a627d42eSDarren Tucker 		free(signature);
1587ea845e4SDamien Miller 	}
1590c50992aSdjm@openbsd.org  fail:
1600c50992aSdjm@openbsd.org 	free(blob);
1610c50992aSdjm@openbsd.org 	sshkey_free(key);
162ff55f4adSmarkus@openbsd.org 	sshbuf_free(msg);
1637ea845e4SDamien Miller 	return (ret);
1647ea845e4SDamien Miller }
1657ea845e4SDamien Miller 
166e2cb445dSDamien Miller #ifdef HAVE_EC_KEY_METHOD_NEW
16793f02107Sdjm@openbsd.org static ECDSA_SIG *
ecdsa_do_sign(const unsigned char * dgst,int dgst_len,const BIGNUM * inv,const BIGNUM * rp,EC_KEY * ec)16893f02107Sdjm@openbsd.org ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
16993f02107Sdjm@openbsd.org     const BIGNUM *rp, EC_KEY *ec)
1707ea845e4SDamien Miller {
1710c50992aSdjm@openbsd.org 	struct sshkey *key = NULL;
1720c50992aSdjm@openbsd.org 	struct sshbuf *msg = NULL;
17393f02107Sdjm@openbsd.org 	ECDSA_SIG *ret = NULL;
1740c50992aSdjm@openbsd.org 	const u_char *cp;
1750c50992aSdjm@openbsd.org 	u_char *blob = NULL, *signature = NULL;
1760c50992aSdjm@openbsd.org 	size_t blen, slen = 0;
1770c50992aSdjm@openbsd.org 	int r, nid;
17893f02107Sdjm@openbsd.org 
1790c50992aSdjm@openbsd.org 	nid = sshkey_ecdsa_key_to_nid(ec);
1800c50992aSdjm@openbsd.org 	if (nid < 0) {
181*816036f1Sdjm@openbsd.org 		error_f("couldn't get curve nid");
1820c50992aSdjm@openbsd.org 		goto fail;
18393f02107Sdjm@openbsd.org 	}
1840c50992aSdjm@openbsd.org 
1850c50992aSdjm@openbsd.org 	key = sshkey_new(KEY_UNSPEC);
1860c50992aSdjm@openbsd.org 	if (key == NULL) {
187*816036f1Sdjm@openbsd.org 		error_f("sshkey_new failed");
1880c50992aSdjm@openbsd.org 		goto fail;
1890c50992aSdjm@openbsd.org 	}
1900c50992aSdjm@openbsd.org 	key->ecdsa = ec;
1910c50992aSdjm@openbsd.org 	key->ecdsa_nid = nid;
1920c50992aSdjm@openbsd.org 	key->type = KEY_ECDSA;
1930c50992aSdjm@openbsd.org 	EC_KEY_up_ref(ec);
1940c50992aSdjm@openbsd.org 
1950c50992aSdjm@openbsd.org 	if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
196*816036f1Sdjm@openbsd.org 		error_fr(r, "encode key");
1970c50992aSdjm@openbsd.org 		goto fail;
19893f02107Sdjm@openbsd.org 	}
19993f02107Sdjm@openbsd.org 	if ((msg = sshbuf_new()) == NULL)
200*816036f1Sdjm@openbsd.org 		fatal_f("sshbuf_new failed");
20193f02107Sdjm@openbsd.org 	if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
20293f02107Sdjm@openbsd.org 	    (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
20393f02107Sdjm@openbsd.org 	    (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 ||
20493f02107Sdjm@openbsd.org 	    (r = sshbuf_put_u32(msg, 0)) != 0)
205*816036f1Sdjm@openbsd.org 		fatal_fr(r, "compose");
20693f02107Sdjm@openbsd.org 	send_msg(msg);
20793f02107Sdjm@openbsd.org 	sshbuf_reset(msg);
20893f02107Sdjm@openbsd.org 
20993f02107Sdjm@openbsd.org 	if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) {
21093f02107Sdjm@openbsd.org 		if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
211*816036f1Sdjm@openbsd.org 			fatal_fr(r, "parse");
21293f02107Sdjm@openbsd.org 		cp = signature;
21393f02107Sdjm@openbsd.org 		ret = d2i_ECDSA_SIG(NULL, &cp, slen);
21493f02107Sdjm@openbsd.org 		free(signature);
21593f02107Sdjm@openbsd.org 	}
21693f02107Sdjm@openbsd.org 
2170c50992aSdjm@openbsd.org  fail:
2180c50992aSdjm@openbsd.org 	free(blob);
2190c50992aSdjm@openbsd.org 	sshkey_free(key);
22093f02107Sdjm@openbsd.org 	sshbuf_free(msg);
22193f02107Sdjm@openbsd.org 	return (ret);
22293f02107Sdjm@openbsd.org }
223e2cb445dSDamien Miller #endif /* HAVE_EC_KEY_METHOD_NEW */
22493f02107Sdjm@openbsd.org 
225482d23bcSdjm@openbsd.org static RSA_METHOD	*helper_rsa;
226e2cb445dSDamien Miller #ifdef HAVE_EC_KEY_METHOD_NEW
22793f02107Sdjm@openbsd.org static EC_KEY_METHOD	*helper_ecdsa;
228e2cb445dSDamien Miller #endif /* HAVE_EC_KEY_METHOD_NEW */
22993f02107Sdjm@openbsd.org 
23093f02107Sdjm@openbsd.org /* redirect private key crypto operations to the ssh-pkcs11-helper */
23193f02107Sdjm@openbsd.org static void
wrap_key(struct sshkey * k)23293f02107Sdjm@openbsd.org wrap_key(struct sshkey *k)
23393f02107Sdjm@openbsd.org {
23493f02107Sdjm@openbsd.org 	if (k->type == KEY_RSA)
23593f02107Sdjm@openbsd.org 		RSA_set_method(k->rsa, helper_rsa);
236e2cb445dSDamien Miller #ifdef HAVE_EC_KEY_METHOD_NEW
23793f02107Sdjm@openbsd.org 	else if (k->type == KEY_ECDSA)
23893f02107Sdjm@openbsd.org 		EC_KEY_set_method(k->ecdsa, helper_ecdsa);
239e2cb445dSDamien Miller #endif /* HAVE_EC_KEY_METHOD_NEW */
24093f02107Sdjm@openbsd.org 	else
241*816036f1Sdjm@openbsd.org 		fatal_f("unknown key type");
24293f02107Sdjm@openbsd.org }
24393f02107Sdjm@openbsd.org 
24493f02107Sdjm@openbsd.org static int
pkcs11_start_helper_methods(void)24593f02107Sdjm@openbsd.org pkcs11_start_helper_methods(void)
24693f02107Sdjm@openbsd.org {
247e2cb445dSDamien Miller 	if (helper_rsa != NULL)
24893f02107Sdjm@openbsd.org 		return (0);
24993f02107Sdjm@openbsd.org 
250e2cb445dSDamien Miller #ifdef HAVE_EC_KEY_METHOD_NEW
25193f02107Sdjm@openbsd.org 	int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
25293f02107Sdjm@openbsd.org 	    unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
25393f02107Sdjm@openbsd.org 	if (helper_ecdsa != NULL)
25493f02107Sdjm@openbsd.org 		return (0);
25593f02107Sdjm@openbsd.org 	helper_ecdsa = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
25693f02107Sdjm@openbsd.org 	if (helper_ecdsa == NULL)
25793f02107Sdjm@openbsd.org 		return (-1);
25893f02107Sdjm@openbsd.org 	EC_KEY_METHOD_get_sign(helper_ecdsa, &orig_sign, NULL, NULL);
25993f02107Sdjm@openbsd.org 	EC_KEY_METHOD_set_sign(helper_ecdsa, orig_sign, NULL, ecdsa_do_sign);
260e2cb445dSDamien Miller #endif /* HAVE_EC_KEY_METHOD_NEW */
2617ea845e4SDamien Miller 
262482d23bcSdjm@openbsd.org 	if ((helper_rsa = RSA_meth_dup(RSA_get_default_method())) == NULL)
263*816036f1Sdjm@openbsd.org 		fatal_f("RSA_meth_dup failed");
264482d23bcSdjm@openbsd.org 	if (!RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper") ||
26593f02107Sdjm@openbsd.org 	    !RSA_meth_set_priv_enc(helper_rsa, rsa_encrypt))
266*816036f1Sdjm@openbsd.org 		fatal_f("failed to prepare method");
26793f02107Sdjm@openbsd.org 
2687ea845e4SDamien Miller 	return (0);
2697ea845e4SDamien Miller }
2707ea845e4SDamien Miller 
2717ea845e4SDamien Miller static int
pkcs11_start_helper(void)2727ea845e4SDamien Miller pkcs11_start_helper(void)
2737ea845e4SDamien Miller {
2747ea845e4SDamien Miller 	int pair[2];
275c7670b09Sdjm@openbsd.org 	char *helper, *verbosity = NULL;
276c7670b09Sdjm@openbsd.org 
277c7670b09Sdjm@openbsd.org 	if (log_level_get() >= SYSLOG_LEVEL_DEBUG1)
278c7670b09Sdjm@openbsd.org 		verbosity = "-vvv";
2797ea845e4SDamien Miller 
28093f02107Sdjm@openbsd.org 	if (pkcs11_start_helper_methods() == -1) {
28193f02107Sdjm@openbsd.org 		error("pkcs11_start_helper_methods failed");
28293f02107Sdjm@openbsd.org 		return (-1);
28393f02107Sdjm@openbsd.org 	}
28493f02107Sdjm@openbsd.org 
2857ea845e4SDamien Miller 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
2867ea845e4SDamien Miller 		error("socketpair: %s", strerror(errno));
2877ea845e4SDamien Miller 		return (-1);
2887ea845e4SDamien Miller 	}
2897ea845e4SDamien Miller 	if ((pid = fork()) == -1) {
2907ea845e4SDamien Miller 		error("fork: %s", strerror(errno));
2917ea845e4SDamien Miller 		return (-1);
2927ea845e4SDamien Miller 	} else if (pid == 0) {
2937ea845e4SDamien Miller 		if ((dup2(pair[1], STDIN_FILENO) == -1) ||
2947ea845e4SDamien Miller 		    (dup2(pair[1], STDOUT_FILENO) == -1)) {
2957ea845e4SDamien Miller 			fprintf(stderr, "dup2: %s\n", strerror(errno));
2967ea845e4SDamien Miller 			_exit(1);
2977ea845e4SDamien Miller 		}
2987ea845e4SDamien Miller 		close(pair[0]);
2997ea845e4SDamien Miller 		close(pair[1]);
300854bd867Sdjm@openbsd.org 		helper = getenv("SSH_PKCS11_HELPER");
301854bd867Sdjm@openbsd.org 		if (helper == NULL || strlen(helper) == 0)
302854bd867Sdjm@openbsd.org 			helper = _PATH_SSH_PKCS11_HELPER;
303*816036f1Sdjm@openbsd.org 		debug_f("starting %s %s", helper,
304c7670b09Sdjm@openbsd.org 		    verbosity == NULL ? "" : verbosity);
305c7670b09Sdjm@openbsd.org 		execlp(helper, helper, verbosity, (char *)NULL);
306854bd867Sdjm@openbsd.org 		fprintf(stderr, "exec: %s: %s\n", helper, strerror(errno));
3077ea845e4SDamien Miller 		_exit(1);
3087ea845e4SDamien Miller 	}
3097ea845e4SDamien Miller 	close(pair[1]);
3107ea845e4SDamien Miller 	fd = pair[0];
3117ea845e4SDamien Miller 	return (0);
3127ea845e4SDamien Miller }
3137ea845e4SDamien Miller 
3147ea845e4SDamien Miller int
pkcs11_add_provider(char * name,char * pin,struct sshkey *** keysp,char *** labelsp)31589a8d452Sdjm@openbsd.org pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp,
31689a8d452Sdjm@openbsd.org     char ***labelsp)
3177ea845e4SDamien Miller {
31854d90aceSmarkus@openbsd.org 	struct sshkey *k;
31993f02107Sdjm@openbsd.org 	int r, type;
3207ea845e4SDamien Miller 	u_char *blob;
32189a8d452Sdjm@openbsd.org 	char *label;
322ff55f4adSmarkus@openbsd.org 	size_t blen;
323ff55f4adSmarkus@openbsd.org 	u_int nkeys, i;
324ff55f4adSmarkus@openbsd.org 	struct sshbuf *msg;
3257ea845e4SDamien Miller 
3267ea845e4SDamien Miller 	if (fd < 0 && pkcs11_start_helper() < 0)
3277ea845e4SDamien Miller 		return (-1);
3287ea845e4SDamien Miller 
329ff55f4adSmarkus@openbsd.org 	if ((msg = sshbuf_new()) == NULL)
330*816036f1Sdjm@openbsd.org 		fatal_f("sshbuf_new failed");
331ff55f4adSmarkus@openbsd.org 	if ((r = sshbuf_put_u8(msg, SSH_AGENTC_ADD_SMARTCARD_KEY)) != 0 ||
332ff55f4adSmarkus@openbsd.org 	    (r = sshbuf_put_cstring(msg, name)) != 0 ||
333ff55f4adSmarkus@openbsd.org 	    (r = sshbuf_put_cstring(msg, pin)) != 0)
334*816036f1Sdjm@openbsd.org 		fatal_fr(r, "compose");
335ff55f4adSmarkus@openbsd.org 	send_msg(msg);
336ff55f4adSmarkus@openbsd.org 	sshbuf_reset(msg);
3377ea845e4SDamien Miller 
33893f02107Sdjm@openbsd.org 	type = recv_msg(msg);
33993f02107Sdjm@openbsd.org 	if (type == SSH2_AGENT_IDENTITIES_ANSWER) {
340ff55f4adSmarkus@openbsd.org 		if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
341*816036f1Sdjm@openbsd.org 			fatal_fr(r, "parse nkeys");
342ff55f4adSmarkus@openbsd.org 		*keysp = xcalloc(nkeys, sizeof(struct sshkey *));
34389a8d452Sdjm@openbsd.org 		if (labelsp)
34489a8d452Sdjm@openbsd.org 			*labelsp = xcalloc(nkeys, sizeof(char *));
3457ea845e4SDamien Miller 		for (i = 0; i < nkeys; i++) {
346ff55f4adSmarkus@openbsd.org 			/* XXX clean up properly instead of fatal() */
347ff55f4adSmarkus@openbsd.org 			if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
34889a8d452Sdjm@openbsd.org 			    (r = sshbuf_get_cstring(msg, &label, NULL)) != 0)
349*816036f1Sdjm@openbsd.org 				fatal_fr(r, "parse key");
350ff55f4adSmarkus@openbsd.org 			if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
351*816036f1Sdjm@openbsd.org 				fatal_fr(r, "decode key");
35293f02107Sdjm@openbsd.org 			wrap_key(k);
3537ea845e4SDamien Miller 			(*keysp)[i] = k;
35489a8d452Sdjm@openbsd.org 			if (labelsp)
35589a8d452Sdjm@openbsd.org 				(*labelsp)[i] = label;
35689a8d452Sdjm@openbsd.org 			else
35789a8d452Sdjm@openbsd.org 				free(label);
358a627d42eSDarren Tucker 			free(blob);
3597ea845e4SDamien Miller 		}
36093f02107Sdjm@openbsd.org 	} else if (type == SSH2_AGENT_FAILURE) {
36193f02107Sdjm@openbsd.org 		if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
36293f02107Sdjm@openbsd.org 			nkeys = -1;
3637ea845e4SDamien Miller 	} else {
3647ea845e4SDamien Miller 		nkeys = -1;
3657ea845e4SDamien Miller 	}
366ff55f4adSmarkus@openbsd.org 	sshbuf_free(msg);
3677ea845e4SDamien Miller 	return (nkeys);
3687ea845e4SDamien Miller }
3697ea845e4SDamien Miller 
3707ea845e4SDamien Miller int
pkcs11_del_provider(char * name)3717ea845e4SDamien Miller pkcs11_del_provider(char *name)
3727ea845e4SDamien Miller {
373ff55f4adSmarkus@openbsd.org 	int r, ret = -1;
374ff55f4adSmarkus@openbsd.org 	struct sshbuf *msg;
3757ea845e4SDamien Miller 
376ff55f4adSmarkus@openbsd.org 	if ((msg = sshbuf_new()) == NULL)
377*816036f1Sdjm@openbsd.org 		fatal_f("sshbuf_new failed");
378ff55f4adSmarkus@openbsd.org 	if ((r = sshbuf_put_u8(msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY)) != 0 ||
379ff55f4adSmarkus@openbsd.org 	    (r = sshbuf_put_cstring(msg, name)) != 0 ||
380ff55f4adSmarkus@openbsd.org 	    (r = sshbuf_put_cstring(msg, "")) != 0)
381*816036f1Sdjm@openbsd.org 		fatal_fr(r, "compose");
382ff55f4adSmarkus@openbsd.org 	send_msg(msg);
383ff55f4adSmarkus@openbsd.org 	sshbuf_reset(msg);
3847ea845e4SDamien Miller 
385ff55f4adSmarkus@openbsd.org 	if (recv_msg(msg) == SSH_AGENT_SUCCESS)
3867ea845e4SDamien Miller 		ret = 0;
387ff55f4adSmarkus@openbsd.org 	sshbuf_free(msg);
3887ea845e4SDamien Miller 	return (ret);
3897ea845e4SDamien Miller }
390dfa4156dSDamien Miller 
391dfa4156dSDamien Miller #endif /* ENABLE_PKCS11 */
392