xref: /dragonfly/crypto/openssh/authfd.c (revision ee116499)
1*ee116499SAntonio Huete Jimenez /* $OpenBSD: authfd.c,v 1.130 2022/04/27 11:08:55 dtucker Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Author: Tatu Ylonen <ylo@cs.hut.fi>
418de8d7fSPeter Avalos  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
518de8d7fSPeter Avalos  *                    All rights reserved
618de8d7fSPeter Avalos  * Functions for connecting the local authentication agent.
718de8d7fSPeter Avalos  *
818de8d7fSPeter Avalos  * As far as I am concerned, the code I have written for this software
918de8d7fSPeter Avalos  * can be used freely for any purpose.  Any derived versions of this
1018de8d7fSPeter Avalos  * software must be clearly marked as such, and if the derived work is
1118de8d7fSPeter Avalos  * incompatible with the protocol description in the RFC file, it must be
1218de8d7fSPeter Avalos  * called by a name other than "ssh" or "Secure Shell".
1318de8d7fSPeter Avalos  *
1418de8d7fSPeter Avalos  * SSH2 implementation,
1518de8d7fSPeter Avalos  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
1618de8d7fSPeter Avalos  *
1718de8d7fSPeter Avalos  * Redistribution and use in source and binary forms, with or without
1818de8d7fSPeter Avalos  * modification, are permitted provided that the following conditions
1918de8d7fSPeter Avalos  * are met:
2018de8d7fSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
2118de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer.
2218de8d7fSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
2318de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
2418de8d7fSPeter Avalos  *    documentation and/or other materials provided with the distribution.
2518de8d7fSPeter Avalos  *
2618de8d7fSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2718de8d7fSPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2818de8d7fSPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2918de8d7fSPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
3018de8d7fSPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3118de8d7fSPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3218de8d7fSPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3318de8d7fSPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3418de8d7fSPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3518de8d7fSPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3618de8d7fSPeter Avalos  */
3718de8d7fSPeter Avalos 
3818de8d7fSPeter Avalos #include "includes.h"
3918de8d7fSPeter Avalos 
4018de8d7fSPeter Avalos #include <sys/types.h>
4118de8d7fSPeter Avalos #include <sys/un.h>
4218de8d7fSPeter Avalos #include <sys/socket.h>
4318de8d7fSPeter Avalos 
4418de8d7fSPeter Avalos #include <fcntl.h>
4518de8d7fSPeter Avalos #include <stdlib.h>
4618de8d7fSPeter Avalos #include <signal.h>
4718de8d7fSPeter Avalos #include <string.h>
480cbfa66cSDaniel Fojt #include <stdarg.h>
4918de8d7fSPeter Avalos #include <unistd.h>
50e9778795SPeter Avalos #include <errno.h>
5118de8d7fSPeter Avalos 
5218de8d7fSPeter Avalos #include "xmalloc.h"
5318de8d7fSPeter Avalos #include "ssh.h"
54e9778795SPeter Avalos #include "sshbuf.h"
55e9778795SPeter Avalos #include "sshkey.h"
5618de8d7fSPeter Avalos #include "authfd.h"
5718de8d7fSPeter Avalos #include "cipher.h"
5818de8d7fSPeter Avalos #include "compat.h"
5918de8d7fSPeter Avalos #include "log.h"
6018de8d7fSPeter Avalos #include "atomicio.h"
6118de8d7fSPeter Avalos #include "misc.h"
62e9778795SPeter Avalos #include "ssherr.h"
6318de8d7fSPeter Avalos 
64e9778795SPeter Avalos #define MAX_AGENT_IDENTITIES	2048		/* Max keys in agent reply */
65e9778795SPeter Avalos #define MAX_AGENT_REPLY_LEN	(256 * 1024)	/* Max bytes in agent reply */
6618de8d7fSPeter Avalos 
6718de8d7fSPeter Avalos /* macro to check for "agent failure" message */
6818de8d7fSPeter Avalos #define agent_failed(x) \
69e9778795SPeter Avalos     ((x == SSH_AGENT_FAILURE) || \
70e9778795SPeter Avalos     (x == SSH_COM_AGENT2_FAILURE) || \
7118de8d7fSPeter Avalos     (x == SSH2_AGENT_FAILURE))
7218de8d7fSPeter Avalos 
73e9778795SPeter Avalos /* Convert success/failure response from agent to a err.h status */
74e9778795SPeter Avalos static int
decode_reply(u_char type)75e9778795SPeter Avalos decode_reply(u_char type)
7618de8d7fSPeter Avalos {
77e9778795SPeter Avalos 	if (agent_failed(type))
78e9778795SPeter Avalos 		return SSH_ERR_AGENT_FAILURE;
79e9778795SPeter Avalos 	else if (type == SSH_AGENT_SUCCESS)
8018de8d7fSPeter Avalos 		return 0;
81e9778795SPeter Avalos 	else
82e9778795SPeter Avalos 		return SSH_ERR_INVALID_FORMAT;
8318de8d7fSPeter Avalos }
8418de8d7fSPeter Avalos 
850cbfa66cSDaniel Fojt /*
860cbfa66cSDaniel Fojt  * Opens an authentication socket at the provided path and stores the file
870cbfa66cSDaniel Fojt  * descriptor in fdp. Returns 0 on success and an error on failure.
880cbfa66cSDaniel Fojt  */
8918de8d7fSPeter Avalos int
ssh_get_authentication_socket_path(const char * authsocket,int * fdp)900cbfa66cSDaniel Fojt ssh_get_authentication_socket_path(const char *authsocket, int *fdp)
9118de8d7fSPeter Avalos {
92e9778795SPeter Avalos 	int sock, oerrno;
9318de8d7fSPeter Avalos 	struct sockaddr_un sunaddr;
9418de8d7fSPeter Avalos 
95*ee116499SAntonio Huete Jimenez 	debug3_f("path '%s'", authsocket);
9636e94dc5SPeter Avalos 	memset(&sunaddr, 0, sizeof(sunaddr));
9718de8d7fSPeter Avalos 	sunaddr.sun_family = AF_UNIX;
9818de8d7fSPeter Avalos 	strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
9918de8d7fSPeter Avalos 
1000cbfa66cSDaniel Fojt 	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
101e9778795SPeter Avalos 		return SSH_ERR_SYSTEM_ERROR;
10218de8d7fSPeter Avalos 
10318de8d7fSPeter Avalos 	/* close on exec */
104e9778795SPeter Avalos 	if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 ||
1050cbfa66cSDaniel Fojt 	    connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
106e9778795SPeter Avalos 		oerrno = errno;
10718de8d7fSPeter Avalos 		close(sock);
108e9778795SPeter Avalos 		errno = oerrno;
109e9778795SPeter Avalos 		return SSH_ERR_SYSTEM_ERROR;
11018de8d7fSPeter Avalos 	}
111e9778795SPeter Avalos 	if (fdp != NULL)
112e9778795SPeter Avalos 		*fdp = sock;
113e9778795SPeter Avalos 	else
11418de8d7fSPeter Avalos 		close(sock);
115e9778795SPeter Avalos 	return 0;
11618de8d7fSPeter Avalos }
11718de8d7fSPeter Avalos 
1180cbfa66cSDaniel Fojt /*
1190cbfa66cSDaniel Fojt  * Opens the default authentication socket and stores the file descriptor in
1200cbfa66cSDaniel Fojt  * fdp. Returns 0 on success and an error on failure.
1210cbfa66cSDaniel Fojt  */
1220cbfa66cSDaniel Fojt int
ssh_get_authentication_socket(int * fdp)1230cbfa66cSDaniel Fojt ssh_get_authentication_socket(int *fdp)
1240cbfa66cSDaniel Fojt {
1250cbfa66cSDaniel Fojt 	const char *authsocket;
1260cbfa66cSDaniel Fojt 
1270cbfa66cSDaniel Fojt 	if (fdp != NULL)
1280cbfa66cSDaniel Fojt 		*fdp = -1;
1290cbfa66cSDaniel Fojt 
1300cbfa66cSDaniel Fojt 	authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
1310cbfa66cSDaniel Fojt 	if (authsocket == NULL || *authsocket == '\0')
1320cbfa66cSDaniel Fojt 		return SSH_ERR_AGENT_NOT_PRESENT;
1330cbfa66cSDaniel Fojt 
1340cbfa66cSDaniel Fojt 	return ssh_get_authentication_socket_path(authsocket, fdp);
1350cbfa66cSDaniel Fojt }
1360cbfa66cSDaniel Fojt 
137e9778795SPeter Avalos /* Communicate with agent: send request and read reply */
13818de8d7fSPeter Avalos static int
ssh_request_reply(int sock,struct sshbuf * request,struct sshbuf * reply)139e9778795SPeter Avalos ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply)
14018de8d7fSPeter Avalos {
141e9778795SPeter Avalos 	int r;
142e9778795SPeter Avalos 	size_t l, len;
14318de8d7fSPeter Avalos 	char buf[1024];
14418de8d7fSPeter Avalos 
14518de8d7fSPeter Avalos 	/* Get the length of the message, and format it in the buffer. */
146e9778795SPeter Avalos 	len = sshbuf_len(request);
147664f4763Szrj 	POKE_U32(buf, len);
14818de8d7fSPeter Avalos 
14918de8d7fSPeter Avalos 	/* Send the length and then the packet to the agent. */
150e9778795SPeter Avalos 	if (atomicio(vwrite, sock, buf, 4) != 4 ||
151664f4763Szrj 	    atomicio(vwrite, sock, sshbuf_mutable_ptr(request),
152e9778795SPeter Avalos 	    sshbuf_len(request)) != sshbuf_len(request))
153e9778795SPeter Avalos 		return SSH_ERR_AGENT_COMMUNICATION;
15418de8d7fSPeter Avalos 	/*
15518de8d7fSPeter Avalos 	 * Wait for response from the agent.  First read the length of the
15618de8d7fSPeter Avalos 	 * response packet.
15718de8d7fSPeter Avalos 	 */
158e9778795SPeter Avalos 	if (atomicio(read, sock, buf, 4) != 4)
159e9778795SPeter Avalos 	    return SSH_ERR_AGENT_COMMUNICATION;
16018de8d7fSPeter Avalos 
16118de8d7fSPeter Avalos 	/* Extract the length, and check it for sanity. */
162664f4763Szrj 	len = PEEK_U32(buf);
163e9778795SPeter Avalos 	if (len > MAX_AGENT_REPLY_LEN)
164e9778795SPeter Avalos 		return SSH_ERR_INVALID_FORMAT;
16518de8d7fSPeter Avalos 
16618de8d7fSPeter Avalos 	/* Read the rest of the response in to the buffer. */
167e9778795SPeter Avalos 	sshbuf_reset(reply);
16818de8d7fSPeter Avalos 	while (len > 0) {
16918de8d7fSPeter Avalos 		l = len;
17018de8d7fSPeter Avalos 		if (l > sizeof(buf))
17118de8d7fSPeter Avalos 			l = sizeof(buf);
172e9778795SPeter Avalos 		if (atomicio(read, sock, buf, l) != l)
173e9778795SPeter Avalos 			return SSH_ERR_AGENT_COMMUNICATION;
174e9778795SPeter Avalos 		if ((r = sshbuf_put(reply, buf, l)) != 0)
175e9778795SPeter Avalos 			return r;
17618de8d7fSPeter Avalos 		len -= l;
17718de8d7fSPeter Avalos 	}
178e9778795SPeter Avalos 	return 0;
17918de8d7fSPeter Avalos }
18018de8d7fSPeter Avalos 
18150a69bb5SSascha Wildner /* Communicate with agent: sent request, read and decode status reply */
18250a69bb5SSascha Wildner static int
ssh_request_reply_decode(int sock,struct sshbuf * request)18350a69bb5SSascha Wildner ssh_request_reply_decode(int sock, struct sshbuf *request)
18450a69bb5SSascha Wildner {
18550a69bb5SSascha Wildner 	struct sshbuf *reply;
18650a69bb5SSascha Wildner 	int r;
18750a69bb5SSascha Wildner 	u_char type;
18850a69bb5SSascha Wildner 
18950a69bb5SSascha Wildner 	if ((reply = sshbuf_new()) == NULL)
19050a69bb5SSascha Wildner 		return SSH_ERR_ALLOC_FAIL;
19150a69bb5SSascha Wildner 	if ((r = ssh_request_reply(sock, request, reply)) != 0 ||
19250a69bb5SSascha Wildner 	    (r = sshbuf_get_u8(reply, &type)) != 0 ||
19350a69bb5SSascha Wildner 	    (r = decode_reply(type)) != 0)
19450a69bb5SSascha Wildner 		goto out;
19550a69bb5SSascha Wildner 	/* success */
19650a69bb5SSascha Wildner 	r = 0;
19750a69bb5SSascha Wildner  out:
19850a69bb5SSascha Wildner 	sshbuf_free(reply);
19950a69bb5SSascha Wildner 	return r;
20050a69bb5SSascha Wildner }
20150a69bb5SSascha Wildner 
20218de8d7fSPeter Avalos /*
20318de8d7fSPeter Avalos  * Closes the agent socket if it should be closed (depends on how it was
20418de8d7fSPeter Avalos  * obtained).  The argument must have been returned by
20518de8d7fSPeter Avalos  * ssh_get_authentication_socket().
20618de8d7fSPeter Avalos  */
20718de8d7fSPeter Avalos void
ssh_close_authentication_socket(int sock)20818de8d7fSPeter Avalos ssh_close_authentication_socket(int sock)
20918de8d7fSPeter Avalos {
21018de8d7fSPeter Avalos 	if (getenv(SSH_AUTHSOCKET_ENV_NAME))
21118de8d7fSPeter Avalos 		close(sock);
21218de8d7fSPeter Avalos }
21318de8d7fSPeter Avalos 
21418de8d7fSPeter Avalos /* Lock/unlock agent */
21518de8d7fSPeter Avalos int
ssh_lock_agent(int sock,int lock,const char * password)216e9778795SPeter Avalos ssh_lock_agent(int sock, int lock, const char *password)
21718de8d7fSPeter Avalos {
218e9778795SPeter Avalos 	int r;
219e9778795SPeter Avalos 	u_char type = lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK;
220e9778795SPeter Avalos 	struct sshbuf *msg;
22118de8d7fSPeter Avalos 
222e9778795SPeter Avalos 	if ((msg = sshbuf_new()) == NULL)
223e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
224e9778795SPeter Avalos 	if ((r = sshbuf_put_u8(msg, type)) != 0 ||
22550a69bb5SSascha Wildner 	    (r = sshbuf_put_cstring(msg, password)) != 0 ||
22650a69bb5SSascha Wildner 	    (r = ssh_request_reply_decode(sock, msg)) != 0)
227e9778795SPeter Avalos 		goto out;
22850a69bb5SSascha Wildner 	/* success */
22950a69bb5SSascha Wildner 	r = 0;
230e9778795SPeter Avalos  out:
231e9778795SPeter Avalos 	sshbuf_free(msg);
232e9778795SPeter Avalos 	return r;
23318de8d7fSPeter Avalos }
234e9778795SPeter Avalos 
235e9778795SPeter Avalos 
236e9778795SPeter Avalos static int
deserialise_identity2(struct sshbuf * ids,struct sshkey ** keyp,char ** commentp)237e9778795SPeter Avalos deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
238e9778795SPeter Avalos {
239e9778795SPeter Avalos 	int r;
240e9778795SPeter Avalos 	char *comment = NULL;
241e9778795SPeter Avalos 	const u_char *blob;
242e9778795SPeter Avalos 	size_t blen;
243e9778795SPeter Avalos 
244e9778795SPeter Avalos 	if ((r = sshbuf_get_string_direct(ids, &blob, &blen)) != 0 ||
245e9778795SPeter Avalos 	    (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0)
246e9778795SPeter Avalos 		goto out;
247e9778795SPeter Avalos 	if ((r = sshkey_from_blob(blob, blen, keyp)) != 0)
248e9778795SPeter Avalos 		goto out;
249e9778795SPeter Avalos 	if (commentp != NULL) {
250e9778795SPeter Avalos 		*commentp = comment;
251e9778795SPeter Avalos 		comment = NULL;
252e9778795SPeter Avalos 	}
253e9778795SPeter Avalos 	r = 0;
254e9778795SPeter Avalos  out:
255e9778795SPeter Avalos 	free(comment);
256e9778795SPeter Avalos 	return r;
25718de8d7fSPeter Avalos }
25818de8d7fSPeter Avalos 
25918de8d7fSPeter Avalos /*
260e9778795SPeter Avalos  * Fetch list of identities held by the agent.
26118de8d7fSPeter Avalos  */
26218de8d7fSPeter Avalos int
ssh_fetch_identitylist(int sock,struct ssh_identitylist ** idlp)263ce74bacaSMatthew Dillon ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp)
26418de8d7fSPeter Avalos {
265ce74bacaSMatthew Dillon 	u_char type;
266e9778795SPeter Avalos 	u_int32_t num, i;
267e9778795SPeter Avalos 	struct sshbuf *msg;
268e9778795SPeter Avalos 	struct ssh_identitylist *idl = NULL;
269e9778795SPeter Avalos 	int r;
27018de8d7fSPeter Avalos 
27118de8d7fSPeter Avalos 	/*
27218de8d7fSPeter Avalos 	 * Send a message to the agent requesting for a list of the
27318de8d7fSPeter Avalos 	 * identities it can represent.
27418de8d7fSPeter Avalos 	 */
275e9778795SPeter Avalos 	if ((msg = sshbuf_new()) == NULL)
276e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
277ce74bacaSMatthew Dillon 	if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_REQUEST_IDENTITIES)) != 0)
278e9778795SPeter Avalos 		goto out;
27918de8d7fSPeter Avalos 
280e9778795SPeter Avalos 	if ((r = ssh_request_reply(sock, msg, msg)) != 0)
281e9778795SPeter Avalos 		goto out;
28218de8d7fSPeter Avalos 
28318de8d7fSPeter Avalos 	/* Get message type, and verify that we got a proper answer. */
284e9778795SPeter Avalos 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
285e9778795SPeter Avalos 		goto out;
28618de8d7fSPeter Avalos 	if (agent_failed(type)) {
287e9778795SPeter Avalos 		r = SSH_ERR_AGENT_FAILURE;
288e9778795SPeter Avalos 		goto out;
289ce74bacaSMatthew Dillon 	} else if (type != SSH2_AGENT_IDENTITIES_ANSWER) {
290e9778795SPeter Avalos 		r = SSH_ERR_INVALID_FORMAT;
291e9778795SPeter Avalos 		goto out;
29218de8d7fSPeter Avalos 	}
29318de8d7fSPeter Avalos 
29418de8d7fSPeter Avalos 	/* Get the number of entries in the response and check it for sanity. */
295e9778795SPeter Avalos 	if ((r = sshbuf_get_u32(msg, &num)) != 0)
296e9778795SPeter Avalos 		goto out;
297e9778795SPeter Avalos 	if (num > MAX_AGENT_IDENTITIES) {
298e9778795SPeter Avalos 		r = SSH_ERR_INVALID_FORMAT;
299e9778795SPeter Avalos 		goto out;
300e9778795SPeter Avalos 	}
301e9778795SPeter Avalos 	if (num == 0) {
302e9778795SPeter Avalos 		r = SSH_ERR_AGENT_NO_IDENTITIES;
303e9778795SPeter Avalos 		goto out;
30418de8d7fSPeter Avalos 	}
30518de8d7fSPeter Avalos 
306e9778795SPeter Avalos 	/* Deserialise the response into a list of keys/comments */
307e9778795SPeter Avalos 	if ((idl = calloc(1, sizeof(*idl))) == NULL ||
308e9778795SPeter Avalos 	    (idl->keys = calloc(num, sizeof(*idl->keys))) == NULL ||
309e9778795SPeter Avalos 	    (idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) {
310e9778795SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
311e9778795SPeter Avalos 		goto out;
31218de8d7fSPeter Avalos 	}
313e9778795SPeter Avalos 	for (i = 0; i < num;) {
314ce74bacaSMatthew Dillon 		if ((r = deserialise_identity2(msg, &(idl->keys[i]),
315ce74bacaSMatthew Dillon 		    &(idl->comments[i]))) != 0) {
316e9778795SPeter Avalos 			if (r == SSH_ERR_KEY_TYPE_UNKNOWN) {
317e9778795SPeter Avalos 				/* Gracefully skip unknown key types */
318e9778795SPeter Avalos 				num--;
319e9778795SPeter Avalos 				continue;
320e9778795SPeter Avalos 			} else
321e9778795SPeter Avalos 				goto out;
32218de8d7fSPeter Avalos 		}
323e9778795SPeter Avalos 		i++;
324e9778795SPeter Avalos 	}
325e9778795SPeter Avalos 	idl->nkeys = num;
326e9778795SPeter Avalos 	*idlp = idl;
327e9778795SPeter Avalos 	idl = NULL;
328e9778795SPeter Avalos 	r = 0;
329e9778795SPeter Avalos  out:
330e9778795SPeter Avalos 	sshbuf_free(msg);
331e9778795SPeter Avalos 	if (idl != NULL)
332e9778795SPeter Avalos 		ssh_free_identitylist(idl);
333e9778795SPeter Avalos 	return r;
334e9778795SPeter Avalos }
335e9778795SPeter Avalos 
336e9778795SPeter Avalos void
ssh_free_identitylist(struct ssh_identitylist * idl)337e9778795SPeter Avalos ssh_free_identitylist(struct ssh_identitylist *idl)
338e9778795SPeter Avalos {
339e9778795SPeter Avalos 	size_t i;
340e9778795SPeter Avalos 
341e9778795SPeter Avalos 	if (idl == NULL)
342e9778795SPeter Avalos 		return;
343e9778795SPeter Avalos 	for (i = 0; i < idl->nkeys; i++) {
344e9778795SPeter Avalos 		if (idl->keys != NULL)
345e9778795SPeter Avalos 			sshkey_free(idl->keys[i]);
346e9778795SPeter Avalos 		if (idl->comments != NULL)
347e9778795SPeter Avalos 			free(idl->comments[i]);
348e9778795SPeter Avalos 	}
3490cbfa66cSDaniel Fojt 	free(idl->keys);
3500cbfa66cSDaniel Fojt 	free(idl->comments);
351e9778795SPeter Avalos 	free(idl);
35218de8d7fSPeter Avalos }
35318de8d7fSPeter Avalos 
35418de8d7fSPeter Avalos /*
3550cbfa66cSDaniel Fojt  * Check if the ssh agent has a given key.
3560cbfa66cSDaniel Fojt  * Returns 0 if found, or a negative SSH_ERR_* error code on failure.
3570cbfa66cSDaniel Fojt  */
3580cbfa66cSDaniel Fojt int
ssh_agent_has_key(int sock,const struct sshkey * key)35950a69bb5SSascha Wildner ssh_agent_has_key(int sock, const struct sshkey *key)
3600cbfa66cSDaniel Fojt {
3610cbfa66cSDaniel Fojt 	int r, ret = SSH_ERR_KEY_NOT_FOUND;
3620cbfa66cSDaniel Fojt 	size_t i;
3630cbfa66cSDaniel Fojt 	struct ssh_identitylist *idlist = NULL;
3640cbfa66cSDaniel Fojt 
3650cbfa66cSDaniel Fojt 	if ((r = ssh_fetch_identitylist(sock, &idlist)) != 0) {
3660cbfa66cSDaniel Fojt 		return r;
3670cbfa66cSDaniel Fojt 	}
3680cbfa66cSDaniel Fojt 
3690cbfa66cSDaniel Fojt 	for (i = 0; i < idlist->nkeys; i++) {
3700cbfa66cSDaniel Fojt 		if (sshkey_equal_public(idlist->keys[i], key)) {
3710cbfa66cSDaniel Fojt 			ret = 0;
3720cbfa66cSDaniel Fojt 			break;
3730cbfa66cSDaniel Fojt 		}
3740cbfa66cSDaniel Fojt 	}
3750cbfa66cSDaniel Fojt 
3760cbfa66cSDaniel Fojt 	ssh_free_identitylist(idlist);
3770cbfa66cSDaniel Fojt 	return ret;
3780cbfa66cSDaniel Fojt }
3790cbfa66cSDaniel Fojt 
3800cbfa66cSDaniel Fojt /*
381e9778795SPeter Avalos  * Sends a challenge (typically from a server via ssh(1)) to the agent,
382e9778795SPeter Avalos  * and waits for a response from the agent.
383e9778795SPeter Avalos  * Returns true (non-zero) if the agent gave the correct answer, zero
384e9778795SPeter Avalos  * otherwise.
38518de8d7fSPeter Avalos  */
38618de8d7fSPeter Avalos 
38718de8d7fSPeter Avalos 
388664f4763Szrj /* encode signature algorithm in flag bits, so we can keep the msg format */
389e9778795SPeter Avalos static u_int
agent_encode_alg(const struct sshkey * key,const char * alg)390ce74bacaSMatthew Dillon agent_encode_alg(const struct sshkey *key, const char *alg)
39118de8d7fSPeter Avalos {
392664f4763Szrj 	if (alg != NULL && sshkey_type_plain(key->type) == KEY_RSA) {
393664f4763Szrj 		if (strcmp(alg, "rsa-sha2-256") == 0 ||
394664f4763Szrj 		    strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0)
395e9778795SPeter Avalos 			return SSH_AGENT_RSA_SHA2_256;
396664f4763Szrj 		if (strcmp(alg, "rsa-sha2-512") == 0 ||
397664f4763Szrj 		    strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0)
398e9778795SPeter Avalos 			return SSH_AGENT_RSA_SHA2_512;
39918de8d7fSPeter Avalos 	}
400e9778795SPeter Avalos 	return 0;
401e9778795SPeter Avalos }
402e9778795SPeter Avalos 
403e9778795SPeter Avalos /* ask agent to sign data, returns err.h code on error, 0 on success */
404e9778795SPeter Avalos int
ssh_agent_sign(int sock,const struct sshkey * key,u_char ** sigp,size_t * lenp,const u_char * data,size_t datalen,const char * alg,u_int compat)405ce74bacaSMatthew Dillon ssh_agent_sign(int sock, const struct sshkey *key,
406e9778795SPeter Avalos     u_char **sigp, size_t *lenp,
407e9778795SPeter Avalos     const u_char *data, size_t datalen, const char *alg, u_int compat)
408e9778795SPeter Avalos {
409e9778795SPeter Avalos 	struct sshbuf *msg;
410664f4763Szrj 	u_char *sig = NULL, type = 0;
411664f4763Szrj 	size_t len = 0;
412e9778795SPeter Avalos 	u_int flags = 0;
413e9778795SPeter Avalos 	int r = SSH_ERR_INTERNAL_ERROR;
414e9778795SPeter Avalos 
415e9778795SPeter Avalos 	*sigp = NULL;
416e9778795SPeter Avalos 	*lenp = 0;
417e9778795SPeter Avalos 
418e9778795SPeter Avalos 	if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
419e9778795SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
420e9778795SPeter Avalos 	if ((msg = sshbuf_new()) == NULL)
421e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
422e9778795SPeter Avalos 	flags |= agent_encode_alg(key, alg);
423e9778795SPeter Avalos 	if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
424664f4763Szrj 	    (r = sshkey_puts(key, msg)) != 0 ||
425e9778795SPeter Avalos 	    (r = sshbuf_put_string(msg, data, datalen)) != 0 ||
426e9778795SPeter Avalos 	    (r = sshbuf_put_u32(msg, flags)) != 0)
427e9778795SPeter Avalos 		goto out;
428e9778795SPeter Avalos 	if ((r = ssh_request_reply(sock, msg, msg)) != 0)
429e9778795SPeter Avalos 		goto out;
430e9778795SPeter Avalos 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
431e9778795SPeter Avalos 		goto out;
43218de8d7fSPeter Avalos 	if (agent_failed(type)) {
433e9778795SPeter Avalos 		r = SSH_ERR_AGENT_FAILURE;
434e9778795SPeter Avalos 		goto out;
43518de8d7fSPeter Avalos 	} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
436e9778795SPeter Avalos 		r = SSH_ERR_INVALID_FORMAT;
437e9778795SPeter Avalos 		goto out;
43818de8d7fSPeter Avalos 	}
439664f4763Szrj 	if ((r = sshbuf_get_string(msg, &sig, &len)) != 0)
440e9778795SPeter Avalos 		goto out;
441664f4763Szrj 	/* Check what we actually got back from the agent. */
442664f4763Szrj 	if ((r = sshkey_check_sigtype(sig, len, alg)) != 0)
443664f4763Szrj 		goto out;
444664f4763Szrj 	/* success */
445664f4763Szrj 	*sigp = sig;
446e9778795SPeter Avalos 	*lenp = len;
447664f4763Szrj 	sig = NULL;
448664f4763Szrj 	len = 0;
449e9778795SPeter Avalos 	r = 0;
450e9778795SPeter Avalos  out:
451664f4763Szrj 	freezero(sig, len);
452e9778795SPeter Avalos 	sshbuf_free(msg);
453e9778795SPeter Avalos 	return r;
45418de8d7fSPeter Avalos }
45518de8d7fSPeter Avalos 
45618de8d7fSPeter Avalos /* Encode key for a message to the agent. */
45718de8d7fSPeter Avalos 
458*ee116499SAntonio Huete Jimenez static int
encode_dest_constraint_hop(struct sshbuf * m,const struct dest_constraint_hop * dch)459*ee116499SAntonio Huete Jimenez encode_dest_constraint_hop(struct sshbuf *m,
460*ee116499SAntonio Huete Jimenez     const struct dest_constraint_hop *dch)
461*ee116499SAntonio Huete Jimenez {
462*ee116499SAntonio Huete Jimenez 	struct sshbuf *b;
463*ee116499SAntonio Huete Jimenez 	u_int i;
464*ee116499SAntonio Huete Jimenez 	int r;
465*ee116499SAntonio Huete Jimenez 
466*ee116499SAntonio Huete Jimenez 	if ((b = sshbuf_new()) == NULL)
467*ee116499SAntonio Huete Jimenez 		return SSH_ERR_ALLOC_FAIL;
468*ee116499SAntonio Huete Jimenez 	if ((r = sshbuf_put_cstring(b, dch->user)) != 0 ||
469*ee116499SAntonio Huete Jimenez 	    (r = sshbuf_put_cstring(b, dch->hostname)) != 0 ||
470*ee116499SAntonio Huete Jimenez 	    (r = sshbuf_put_string(b, NULL, 0)) != 0) /* reserved */
471*ee116499SAntonio Huete Jimenez 		goto out;
472*ee116499SAntonio Huete Jimenez 	for (i = 0; i < dch->nkeys; i++) {
473*ee116499SAntonio Huete Jimenez 		if ((r = sshkey_puts(dch->keys[i], b)) != 0 ||
474*ee116499SAntonio Huete Jimenez 		    (r = sshbuf_put_u8(b, dch->key_is_ca[i] != 0)) != 0)
475*ee116499SAntonio Huete Jimenez 			goto out;
476*ee116499SAntonio Huete Jimenez 	}
477*ee116499SAntonio Huete Jimenez 	if ((r = sshbuf_put_stringb(m, b)) != 0)
478*ee116499SAntonio Huete Jimenez 		goto out;
479*ee116499SAntonio Huete Jimenez 	/* success */
480*ee116499SAntonio Huete Jimenez 	r = 0;
481*ee116499SAntonio Huete Jimenez  out:
482*ee116499SAntonio Huete Jimenez 	sshbuf_free(b);
483*ee116499SAntonio Huete Jimenez 	return r;
484*ee116499SAntonio Huete Jimenez }
485*ee116499SAntonio Huete Jimenez 
486*ee116499SAntonio Huete Jimenez static int
encode_dest_constraint(struct sshbuf * m,const struct dest_constraint * dc)487*ee116499SAntonio Huete Jimenez encode_dest_constraint(struct sshbuf *m, const struct dest_constraint *dc)
488*ee116499SAntonio Huete Jimenez {
489*ee116499SAntonio Huete Jimenez 	struct sshbuf *b;
490*ee116499SAntonio Huete Jimenez 	int r;
491*ee116499SAntonio Huete Jimenez 
492*ee116499SAntonio Huete Jimenez 	if ((b = sshbuf_new()) == NULL)
493*ee116499SAntonio Huete Jimenez 		return SSH_ERR_ALLOC_FAIL;
494*ee116499SAntonio Huete Jimenez 	if ((r = encode_dest_constraint_hop(b, &dc->from) != 0) ||
495*ee116499SAntonio Huete Jimenez 	    (r = encode_dest_constraint_hop(b, &dc->to) != 0) ||
496*ee116499SAntonio Huete Jimenez 	    (r = sshbuf_put_string(b, NULL, 0)) != 0) /* reserved */
497*ee116499SAntonio Huete Jimenez 		goto out;
498*ee116499SAntonio Huete Jimenez 	if ((r = sshbuf_put_stringb(m, b)) != 0)
499*ee116499SAntonio Huete Jimenez 		goto out;
500*ee116499SAntonio Huete Jimenez 	/* success */
501*ee116499SAntonio Huete Jimenez 	r = 0;
502*ee116499SAntonio Huete Jimenez  out:
503*ee116499SAntonio Huete Jimenez 	sshbuf_free(b);
504*ee116499SAntonio Huete Jimenez 	return r;
505*ee116499SAntonio Huete Jimenez }
50618de8d7fSPeter Avalos 
507e9778795SPeter Avalos static int
encode_constraints(struct sshbuf * m,u_int life,u_int confirm,u_int maxsign,const char * provider,struct dest_constraint ** dest_constraints,size_t ndest_constraints)5080cbfa66cSDaniel Fojt encode_constraints(struct sshbuf *m, u_int life, u_int confirm, u_int maxsign,
509*ee116499SAntonio Huete Jimenez     const char *provider, struct dest_constraint **dest_constraints,
510*ee116499SAntonio Huete Jimenez     size_t ndest_constraints)
511e9778795SPeter Avalos {
512e9778795SPeter Avalos 	int r;
513*ee116499SAntonio Huete Jimenez 	struct sshbuf *b = NULL;
514*ee116499SAntonio Huete Jimenez 	size_t i;
515e9778795SPeter Avalos 
516e9778795SPeter Avalos 	if (life != 0) {
517e9778795SPeter Avalos 		if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_LIFETIME)) != 0 ||
518e9778795SPeter Avalos 		    (r = sshbuf_put_u32(m, life)) != 0)
519e9778795SPeter Avalos 			goto out;
520e9778795SPeter Avalos 	}
521e9778795SPeter Avalos 	if (confirm != 0) {
522e9778795SPeter Avalos 		if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0)
523e9778795SPeter Avalos 			goto out;
524e9778795SPeter Avalos 	}
525664f4763Szrj 	if (maxsign != 0) {
526664f4763Szrj 		if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_MAXSIGN)) != 0 ||
527664f4763Szrj 		    (r = sshbuf_put_u32(m, maxsign)) != 0)
528664f4763Szrj 			goto out;
529664f4763Szrj 	}
5300cbfa66cSDaniel Fojt 	if (provider != NULL) {
5310cbfa66cSDaniel Fojt 		if ((r = sshbuf_put_u8(m,
5320cbfa66cSDaniel Fojt 		    SSH_AGENT_CONSTRAIN_EXTENSION)) != 0 ||
5330cbfa66cSDaniel Fojt 		    (r = sshbuf_put_cstring(m,
5340cbfa66cSDaniel Fojt 		    "sk-provider@openssh.com")) != 0 ||
5350cbfa66cSDaniel Fojt 		    (r = sshbuf_put_cstring(m, provider)) != 0)
5360cbfa66cSDaniel Fojt 			goto out;
5370cbfa66cSDaniel Fojt 	}
538*ee116499SAntonio Huete Jimenez 	if (dest_constraints != NULL && ndest_constraints > 0) {
539*ee116499SAntonio Huete Jimenez 		if ((b = sshbuf_new()) == NULL) {
540*ee116499SAntonio Huete Jimenez 			r = SSH_ERR_ALLOC_FAIL;
541*ee116499SAntonio Huete Jimenez 			goto out;
542*ee116499SAntonio Huete Jimenez 		}
543*ee116499SAntonio Huete Jimenez 		for (i = 0; i < ndest_constraints; i++) {
544*ee116499SAntonio Huete Jimenez 			if ((r = encode_dest_constraint(b,
545*ee116499SAntonio Huete Jimenez 			    dest_constraints[i])) != 0)
546*ee116499SAntonio Huete Jimenez 				goto out;
547*ee116499SAntonio Huete Jimenez 		}
548*ee116499SAntonio Huete Jimenez 		if ((r = sshbuf_put_u8(m,
549*ee116499SAntonio Huete Jimenez 		    SSH_AGENT_CONSTRAIN_EXTENSION)) != 0 ||
550*ee116499SAntonio Huete Jimenez 		    (r = sshbuf_put_cstring(m,
551*ee116499SAntonio Huete Jimenez 		    "restrict-destination-v00@openssh.com")) != 0 ||
552*ee116499SAntonio Huete Jimenez 		    (r = sshbuf_put_stringb(m, b)) != 0)
553*ee116499SAntonio Huete Jimenez 			goto out;
554*ee116499SAntonio Huete Jimenez 	}
555e9778795SPeter Avalos 	r = 0;
556e9778795SPeter Avalos  out:
557*ee116499SAntonio Huete Jimenez 	sshbuf_free(b);
558e9778795SPeter Avalos 	return r;
55918de8d7fSPeter Avalos }
56018de8d7fSPeter Avalos 
56118de8d7fSPeter Avalos /*
562e9778795SPeter Avalos  * Adds an identity to the authentication server.
563e9778795SPeter Avalos  * This call is intended only for use by ssh-add(1) and like applications.
56418de8d7fSPeter Avalos  */
56518de8d7fSPeter Avalos int
ssh_add_identity_constrained(int sock,struct sshkey * key,const char * comment,u_int life,u_int confirm,u_int maxsign,const char * provider,struct dest_constraint ** dest_constraints,size_t ndest_constraints)5660cbfa66cSDaniel Fojt ssh_add_identity_constrained(int sock, struct sshkey *key,
5670cbfa66cSDaniel Fojt     const char *comment, u_int life, u_int confirm, u_int maxsign,
568*ee116499SAntonio Huete Jimenez     const char *provider, struct dest_constraint **dest_constraints,
569*ee116499SAntonio Huete Jimenez     size_t ndest_constraints)
57018de8d7fSPeter Avalos {
571e9778795SPeter Avalos 	struct sshbuf *msg;
572*ee116499SAntonio Huete Jimenez 	int r, constrained = (life || confirm || maxsign ||
573*ee116499SAntonio Huete Jimenez 	    provider || dest_constraints);
574e9778795SPeter Avalos 	u_char type;
57518de8d7fSPeter Avalos 
576e9778795SPeter Avalos 	if ((msg = sshbuf_new()) == NULL)
577e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
57818de8d7fSPeter Avalos 
57918de8d7fSPeter Avalos 	switch (key->type) {
58036e94dc5SPeter Avalos #ifdef WITH_OPENSSL
58118de8d7fSPeter Avalos 	case KEY_RSA:
582856ea928SPeter Avalos 	case KEY_RSA_CERT:
58318de8d7fSPeter Avalos 	case KEY_DSA:
584856ea928SPeter Avalos 	case KEY_DSA_CERT:
5859f304aafSPeter Avalos 	case KEY_ECDSA:
5869f304aafSPeter Avalos 	case KEY_ECDSA_CERT:
5870cbfa66cSDaniel Fojt 	case KEY_ECDSA_SK:
5880cbfa66cSDaniel Fojt 	case KEY_ECDSA_SK_CERT:
58936e94dc5SPeter Avalos #endif
59036e94dc5SPeter Avalos 	case KEY_ED25519:
59136e94dc5SPeter Avalos 	case KEY_ED25519_CERT:
5920cbfa66cSDaniel Fojt 	case KEY_ED25519_SK:
5930cbfa66cSDaniel Fojt 	case KEY_ED25519_SK_CERT:
594664f4763Szrj 	case KEY_XMSS:
595664f4763Szrj 	case KEY_XMSS_CERT:
59618de8d7fSPeter Avalos 		type = constrained ?
59718de8d7fSPeter Avalos 		    SSH2_AGENTC_ADD_ID_CONSTRAINED :
59818de8d7fSPeter Avalos 		    SSH2_AGENTC_ADD_IDENTITY;
599e9778795SPeter Avalos 		if ((r = sshbuf_put_u8(msg, type)) != 0 ||
600664f4763Szrj 		    (r = sshkey_private_serialize_maxsign(key, msg, maxsign,
60150a69bb5SSascha Wildner 		    0)) != 0 ||
602664f4763Szrj 		    (r = sshbuf_put_cstring(msg, comment)) != 0)
603e9778795SPeter Avalos 			goto out;
60418de8d7fSPeter Avalos 		break;
60518de8d7fSPeter Avalos 	default:
606e9778795SPeter Avalos 		r = SSH_ERR_INVALID_ARGUMENT;
607e9778795SPeter Avalos 		goto out;
60818de8d7fSPeter Avalos 	}
609e9778795SPeter Avalos 	if (constrained &&
6100cbfa66cSDaniel Fojt 	    (r = encode_constraints(msg, life, confirm, maxsign,
611*ee116499SAntonio Huete Jimenez 	    provider, dest_constraints, ndest_constraints)) != 0)
612e9778795SPeter Avalos 		goto out;
61350a69bb5SSascha Wildner 	if ((r = ssh_request_reply_decode(sock, msg)) != 0)
614e9778795SPeter Avalos 		goto out;
61550a69bb5SSascha Wildner 	/* success */
61650a69bb5SSascha Wildner 	r = 0;
617e9778795SPeter Avalos  out:
618e9778795SPeter Avalos 	sshbuf_free(msg);
619e9778795SPeter Avalos 	return r;
62018de8d7fSPeter Avalos }
62118de8d7fSPeter Avalos 
62218de8d7fSPeter Avalos /*
623e9778795SPeter Avalos  * Removes an identity from the authentication server.
624e9778795SPeter Avalos  * This call is intended only for use by ssh-add(1) and like applications.
62518de8d7fSPeter Avalos  */
62618de8d7fSPeter Avalos int
ssh_remove_identity(int sock,const struct sshkey * key)62750a69bb5SSascha Wildner ssh_remove_identity(int sock, const struct sshkey *key)
62818de8d7fSPeter Avalos {
629e9778795SPeter Avalos 	struct sshbuf *msg;
630e9778795SPeter Avalos 	int r;
63150a69bb5SSascha Wildner 	u_char *blob = NULL;
632e9778795SPeter Avalos 	size_t blen;
63318de8d7fSPeter Avalos 
634e9778795SPeter Avalos 	if ((msg = sshbuf_new()) == NULL)
635e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
63618de8d7fSPeter Avalos 
63736e94dc5SPeter Avalos 	if (key->type != KEY_UNSPEC) {
638e9778795SPeter Avalos 		if ((r = sshkey_to_blob(key, &blob, &blen)) != 0)
639e9778795SPeter Avalos 			goto out;
640e9778795SPeter Avalos 		if ((r = sshbuf_put_u8(msg,
641e9778795SPeter Avalos 		    SSH2_AGENTC_REMOVE_IDENTITY)) != 0 ||
642e9778795SPeter Avalos 		    (r = sshbuf_put_string(msg, blob, blen)) != 0)
643e9778795SPeter Avalos 			goto out;
64418de8d7fSPeter Avalos 	} else {
645e9778795SPeter Avalos 		r = SSH_ERR_INVALID_ARGUMENT;
646e9778795SPeter Avalos 		goto out;
64718de8d7fSPeter Avalos 	}
64850a69bb5SSascha Wildner 	if ((r = ssh_request_reply_decode(sock, msg)) != 0)
649e9778795SPeter Avalos 		goto out;
65050a69bb5SSascha Wildner 	/* success */
65150a69bb5SSascha Wildner 	r = 0;
652e9778795SPeter Avalos  out:
6530cbfa66cSDaniel Fojt 	if (blob != NULL)
6540cbfa66cSDaniel Fojt 		freezero(blob, blen);
655e9778795SPeter Avalos 	sshbuf_free(msg);
656e9778795SPeter Avalos 	return r;
65718de8d7fSPeter Avalos }
65818de8d7fSPeter Avalos 
659e9778795SPeter Avalos /*
660e9778795SPeter Avalos  * Add/remove an token-based identity from the authentication server.
661e9778795SPeter Avalos  * This call is intended only for use by ssh-add(1) and like applications.
662e9778795SPeter Avalos  */
66318de8d7fSPeter Avalos int
ssh_update_card(int sock,int add,const char * reader_id,const char * pin,u_int life,u_int confirm,struct dest_constraint ** dest_constraints,size_t ndest_constraints)664e9778795SPeter Avalos ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
665*ee116499SAntonio Huete Jimenez     u_int life, u_int confirm,
666*ee116499SAntonio Huete Jimenez     struct dest_constraint **dest_constraints, size_t ndest_constraints)
66718de8d7fSPeter Avalos {
668e9778795SPeter Avalos 	struct sshbuf *msg;
669e9778795SPeter Avalos 	int r, constrained = (life || confirm);
670e9778795SPeter Avalos 	u_char type;
67118de8d7fSPeter Avalos 
67218de8d7fSPeter Avalos 	if (add) {
67318de8d7fSPeter Avalos 		type = constrained ?
67418de8d7fSPeter Avalos 		    SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED :
67518de8d7fSPeter Avalos 		    SSH_AGENTC_ADD_SMARTCARD_KEY;
67618de8d7fSPeter Avalos 	} else
67718de8d7fSPeter Avalos 		type = SSH_AGENTC_REMOVE_SMARTCARD_KEY;
67818de8d7fSPeter Avalos 
679e9778795SPeter Avalos 	if ((msg = sshbuf_new()) == NULL)
680e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
681e9778795SPeter Avalos 	if ((r = sshbuf_put_u8(msg, type)) != 0 ||
682e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(msg, reader_id)) != 0 ||
683e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(msg, pin)) != 0)
684e9778795SPeter Avalos 		goto out;
685e9778795SPeter Avalos 	if (constrained &&
686*ee116499SAntonio Huete Jimenez 	    (r = encode_constraints(msg, life, confirm, 0, NULL,
687*ee116499SAntonio Huete Jimenez 	    dest_constraints, ndest_constraints)) != 0)
688e9778795SPeter Avalos 		goto out;
68950a69bb5SSascha Wildner 	if ((r = ssh_request_reply_decode(sock, msg)) != 0)
690e9778795SPeter Avalos 		goto out;
69150a69bb5SSascha Wildner 	/* success */
69250a69bb5SSascha Wildner 	r = 0;
693e9778795SPeter Avalos  out:
694e9778795SPeter Avalos 	sshbuf_free(msg);
695e9778795SPeter Avalos 	return r;
69618de8d7fSPeter Avalos }
69718de8d7fSPeter Avalos 
69818de8d7fSPeter Avalos /*
699e9778795SPeter Avalos  * Removes all identities from the agent.
700e9778795SPeter Avalos  * This call is intended only for use by ssh-add(1) and like applications.
701ce74bacaSMatthew Dillon  *
702ce74bacaSMatthew Dillon  * This supports the SSH protocol 1 message to because, when clearing all
703ce74bacaSMatthew Dillon  * keys from an agent, we generally want to clear both protocol v1 and v2
704ce74bacaSMatthew Dillon  * keys.
70518de8d7fSPeter Avalos  */
70618de8d7fSPeter Avalos int
ssh_remove_all_identities(int sock,int version)707e9778795SPeter Avalos ssh_remove_all_identities(int sock, int version)
70818de8d7fSPeter Avalos {
709e9778795SPeter Avalos 	struct sshbuf *msg;
710e9778795SPeter Avalos 	u_char type = (version == 1) ?
71118de8d7fSPeter Avalos 	    SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
71218de8d7fSPeter Avalos 	    SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
713e9778795SPeter Avalos 	int r;
71418de8d7fSPeter Avalos 
715e9778795SPeter Avalos 	if ((msg = sshbuf_new()) == NULL)
716e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
717e9778795SPeter Avalos 	if ((r = sshbuf_put_u8(msg, type)) != 0)
718e9778795SPeter Avalos 		goto out;
71950a69bb5SSascha Wildner 	if ((r = ssh_request_reply_decode(sock, msg)) != 0)
720e9778795SPeter Avalos 		goto out;
72150a69bb5SSascha Wildner 	/* success */
72250a69bb5SSascha Wildner 	r = 0;
723e9778795SPeter Avalos  out:
724e9778795SPeter Avalos 	sshbuf_free(msg);
725e9778795SPeter Avalos 	return r;
72618de8d7fSPeter Avalos }
727*ee116499SAntonio Huete Jimenez 
728*ee116499SAntonio Huete Jimenez /* Binds a session ID to a hostkey via the initial KEX signature. */
729*ee116499SAntonio Huete Jimenez int
ssh_agent_bind_hostkey(int sock,const struct sshkey * key,const struct sshbuf * session_id,const struct sshbuf * signature,int forwarding)730*ee116499SAntonio Huete Jimenez ssh_agent_bind_hostkey(int sock, const struct sshkey *key,
731*ee116499SAntonio Huete Jimenez     const struct sshbuf *session_id, const struct sshbuf *signature,
732*ee116499SAntonio Huete Jimenez     int forwarding)
733*ee116499SAntonio Huete Jimenez {
734*ee116499SAntonio Huete Jimenez 	struct sshbuf *msg;
735*ee116499SAntonio Huete Jimenez 	int r;
736*ee116499SAntonio Huete Jimenez 
737*ee116499SAntonio Huete Jimenez 	if (key == NULL || session_id == NULL || signature == NULL)
738*ee116499SAntonio Huete Jimenez 		return SSH_ERR_INVALID_ARGUMENT;
739*ee116499SAntonio Huete Jimenez 	if ((msg = sshbuf_new()) == NULL)
740*ee116499SAntonio Huete Jimenez 		return SSH_ERR_ALLOC_FAIL;
741*ee116499SAntonio Huete Jimenez 	if ((r = sshbuf_put_u8(msg, SSH_AGENTC_EXTENSION)) != 0 ||
742*ee116499SAntonio Huete Jimenez 	    (r = sshbuf_put_cstring(msg, "session-bind@openssh.com")) != 0 ||
743*ee116499SAntonio Huete Jimenez 	    (r = sshkey_puts(key, msg)) != 0 ||
744*ee116499SAntonio Huete Jimenez 	    (r = sshbuf_put_stringb(msg, session_id)) != 0 ||
745*ee116499SAntonio Huete Jimenez 	    (r = sshbuf_put_stringb(msg, signature)) != 0 ||
746*ee116499SAntonio Huete Jimenez 	    (r = sshbuf_put_u8(msg, forwarding ? 1 : 0)) != 0)
747*ee116499SAntonio Huete Jimenez 		goto out;
748*ee116499SAntonio Huete Jimenez 	if ((r = ssh_request_reply_decode(sock, msg)) != 0)
749*ee116499SAntonio Huete Jimenez 		goto out;
750*ee116499SAntonio Huete Jimenez 	/* success */
751*ee116499SAntonio Huete Jimenez 	r = 0;
752*ee116499SAntonio Huete Jimenez  out:
753*ee116499SAntonio Huete Jimenez 	sshbuf_free(msg);
754*ee116499SAntonio Huete Jimenez 	return r;
755*ee116499SAntonio Huete Jimenez }
756