Home | History | Annotate | Download | only in openssh
      1 /* $OpenBSD: authfd.c,v 1.100 2015/12/04 16:41:28 markus Exp $ */
      2 /*
      3  * Author: Tatu Ylonen <ylo (at) cs.hut.fi>
      4  * Copyright (c) 1995 Tatu Ylonen <ylo (at) cs.hut.fi>, Espoo, Finland
      5  *                    All rights reserved
      6  * Functions for connecting the local authentication agent.
      7  *
      8  * As far as I am concerned, the code I have written for this software
      9  * can be used freely for any purpose.  Any derived versions of this
     10  * software must be clearly marked as such, and if the derived work is
     11  * incompatible with the protocol description in the RFC file, it must be
     12  * called by a name other than "ssh" or "Secure Shell".
     13  *
     14  * SSH2 implementation,
     15  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
     16  *
     17  * Redistribution and use in source and binary forms, with or without
     18  * modification, are permitted provided that the following conditions
     19  * are met:
     20  * 1. Redistributions of source code must retain the above copyright
     21  *    notice, this list of conditions and the following disclaimer.
     22  * 2. Redistributions in binary form must reproduce the above copyright
     23  *    notice, this list of conditions and the following disclaimer in the
     24  *    documentation and/or other materials provided with the distribution.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     29  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     31  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     36  */
     37 
     38 #include "includes.h"
     39 
     40 #include <sys/types.h>
     41 #include <sys/un.h>
     42 #include <sys/socket.h>
     43 
     44 #include <fcntl.h>
     45 #include <stdlib.h>
     46 #include <signal.h>
     47 #include <stdarg.h>
     48 #include <string.h>
     49 #include <unistd.h>
     50 #include <errno.h>
     51 
     52 #include "xmalloc.h"
     53 #include "ssh.h"
     54 #include "rsa.h"
     55 #include "sshbuf.h"
     56 #include "sshkey.h"
     57 #include "authfd.h"
     58 #include "cipher.h"
     59 #include "compat.h"
     60 #include "log.h"
     61 #include "atomicio.h"
     62 #include "misc.h"
     63 #include "ssherr.h"
     64 
     65 #define MAX_AGENT_IDENTITIES	2048		/* Max keys in agent reply */
     66 #define MAX_AGENT_REPLY_LEN	(256 * 1024) 	/* Max bytes in agent reply */
     67 
     68 /* macro to check for "agent failure" message */
     69 #define agent_failed(x) \
     70     ((x == SSH_AGENT_FAILURE) || \
     71     (x == SSH_COM_AGENT2_FAILURE) || \
     72     (x == SSH2_AGENT_FAILURE))
     73 
     74 /* Convert success/failure response from agent to a err.h status */
     75 static int
     76 decode_reply(u_char type)
     77 {
     78 	if (agent_failed(type))
     79 		return SSH_ERR_AGENT_FAILURE;
     80 	else if (type == SSH_AGENT_SUCCESS)
     81 		return 0;
     82 	else
     83 		return SSH_ERR_INVALID_FORMAT;
     84 }
     85 
     86 /* Returns the number of the authentication fd, or -1 if there is none. */
     87 int
     88 ssh_get_authentication_socket(int *fdp)
     89 {
     90 	const char *authsocket;
     91 	int sock, oerrno;
     92 	struct sockaddr_un sunaddr;
     93 
     94 	if (fdp != NULL)
     95 		*fdp = -1;
     96 
     97 	authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
     98 	if (!authsocket)
     99 		return SSH_ERR_AGENT_NOT_PRESENT;
    100 
    101 	memset(&sunaddr, 0, sizeof(sunaddr));
    102 	sunaddr.sun_family = AF_UNIX;
    103 	strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
    104 
    105 	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
    106 		return SSH_ERR_SYSTEM_ERROR;
    107 
    108 	/* close on exec */
    109 	if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 ||
    110 	    connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
    111 		oerrno = errno;
    112 		close(sock);
    113 		errno = oerrno;
    114 		return SSH_ERR_SYSTEM_ERROR;
    115 	}
    116 	if (fdp != NULL)
    117 		*fdp = sock;
    118 	else
    119 		close(sock);
    120 	return 0;
    121 }
    122 
    123 /* Communicate with agent: send request and read reply */
    124 static int
    125 ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply)
    126 {
    127 	int r;
    128 	size_t l, len;
    129 	char buf[1024];
    130 
    131 	/* Get the length of the message, and format it in the buffer. */
    132 	len = sshbuf_len(request);
    133 	put_u32(buf, len);
    134 
    135 	/* Send the length and then the packet to the agent. */
    136 	if (atomicio(vwrite, sock, buf, 4) != 4 ||
    137 	    atomicio(vwrite, sock, (u_char *)sshbuf_ptr(request),
    138 	    sshbuf_len(request)) != sshbuf_len(request))
    139 		return SSH_ERR_AGENT_COMMUNICATION;
    140 	/*
    141 	 * Wait for response from the agent.  First read the length of the
    142 	 * response packet.
    143 	 */
    144 	if (atomicio(read, sock, buf, 4) != 4)
    145 	    return SSH_ERR_AGENT_COMMUNICATION;
    146 
    147 	/* Extract the length, and check it for sanity. */
    148 	len = get_u32(buf);
    149 	if (len > MAX_AGENT_REPLY_LEN)
    150 		return SSH_ERR_INVALID_FORMAT;
    151 
    152 	/* Read the rest of the response in to the buffer. */
    153 	sshbuf_reset(reply);
    154 	while (len > 0) {
    155 		l = len;
    156 		if (l > sizeof(buf))
    157 			l = sizeof(buf);
    158 		if (atomicio(read, sock, buf, l) != l)
    159 			return SSH_ERR_AGENT_COMMUNICATION;
    160 		if ((r = sshbuf_put(reply, buf, l)) != 0)
    161 			return r;
    162 		len -= l;
    163 	}
    164 	return 0;
    165 }
    166 
    167 /*
    168  * Closes the agent socket if it should be closed (depends on how it was
    169  * obtained).  The argument must have been returned by
    170  * ssh_get_authentication_socket().
    171  */
    172 void
    173 ssh_close_authentication_socket(int sock)
    174 {
    175 	if (getenv(SSH_AUTHSOCKET_ENV_NAME))
    176 		close(sock);
    177 }
    178 
    179 /* Lock/unlock agent */
    180 int
    181 ssh_lock_agent(int sock, int lock, const char *password)
    182 {
    183 	int r;
    184 	u_char type = lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK;
    185 	struct sshbuf *msg;
    186 
    187 	if ((msg = sshbuf_new()) == NULL)
    188 		return SSH_ERR_ALLOC_FAIL;
    189 	if ((r = sshbuf_put_u8(msg, type)) != 0 ||
    190 	    (r = sshbuf_put_cstring(msg, password)) != 0)
    191 		goto out;
    192 	if ((r = ssh_request_reply(sock, msg, msg)) != 0)
    193 		goto out;
    194 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
    195 		goto out;
    196 	r = decode_reply(type);
    197  out:
    198 	sshbuf_free(msg);
    199 	return r;
    200 }
    201 
    202 #ifdef WITH_SSH1
    203 static int
    204 deserialise_identity1(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
    205 {
    206 	struct sshkey *key;
    207 	int r, keybits;
    208 	u_int32_t bits;
    209 	char *comment = NULL;
    210 
    211 	if ((key = sshkey_new(KEY_RSA1)) == NULL)
    212 		return SSH_ERR_ALLOC_FAIL;
    213 	if ((r = sshbuf_get_u32(ids, &bits)) != 0 ||
    214 	    (r = sshbuf_get_bignum1(ids, key->rsa->e)) != 0 ||
    215 	    (r = sshbuf_get_bignum1(ids, key->rsa->n)) != 0 ||
    216 	    (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0)
    217 		goto out;
    218 	keybits = BN_num_bits(key->rsa->n);
    219 	/* XXX previously we just warned here. I think we should be strict */
    220 	if (keybits < 0 || bits != (u_int)keybits) {
    221 		r = SSH_ERR_KEY_BITS_MISMATCH;
    222 		goto out;
    223 	}
    224 	if (keyp != NULL) {
    225 		*keyp = key;
    226 		key = NULL;
    227 	}
    228 	if (commentp != NULL) {
    229 		*commentp = comment;
    230 		comment = NULL;
    231 	}
    232 	r = 0;
    233  out:
    234 	sshkey_free(key);
    235 	free(comment);
    236 	return r;
    237 }
    238 #endif
    239 
    240 static int
    241 deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
    242 {
    243 	int r;
    244 	char *comment = NULL;
    245 	const u_char *blob;
    246 	size_t blen;
    247 
    248 	if ((r = sshbuf_get_string_direct(ids, &blob, &blen)) != 0 ||
    249 	    (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0)
    250 		goto out;
    251 	if ((r = sshkey_from_blob(blob, blen, keyp)) != 0)
    252 		goto out;
    253 	if (commentp != NULL) {
    254 		*commentp = comment;
    255 		comment = NULL;
    256 	}
    257 	r = 0;
    258  out:
    259 	free(comment);
    260 	return r;
    261 }
    262 
    263 /*
    264  * Fetch list of identities held by the agent.
    265  */
    266 int
    267 ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp)
    268 {
    269 	u_char type, code1 = 0, code2 = 0;
    270 	u_int32_t num, i;
    271 	struct sshbuf *msg;
    272 	struct ssh_identitylist *idl = NULL;
    273 	int r;
    274 
    275 	/* Determine request and expected response types */
    276 	switch (version) {
    277 	case 1:
    278 		code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
    279 		code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
    280 		break;
    281 	case 2:
    282 		code1 = SSH2_AGENTC_REQUEST_IDENTITIES;
    283 		code2 = SSH2_AGENT_IDENTITIES_ANSWER;
    284 		break;
    285 	default:
    286 		return SSH_ERR_INVALID_ARGUMENT;
    287 	}
    288 
    289 	/*
    290 	 * Send a message to the agent requesting for a list of the
    291 	 * identities it can represent.
    292 	 */
    293 	if ((msg = sshbuf_new()) == NULL)
    294 		return SSH_ERR_ALLOC_FAIL;
    295 	if ((r = sshbuf_put_u8(msg, code1)) != 0)
    296 		goto out;
    297 
    298 	if ((r = ssh_request_reply(sock, msg, msg)) != 0)
    299 		goto out;
    300 
    301 	/* Get message type, and verify that we got a proper answer. */
    302 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
    303 		goto out;
    304 	if (agent_failed(type)) {
    305 		r = SSH_ERR_AGENT_FAILURE;
    306 		goto out;
    307 	} else if (type != code2) {
    308 		r = SSH_ERR_INVALID_FORMAT;
    309 		goto out;
    310 	}
    311 
    312 	/* Get the number of entries in the response and check it for sanity. */
    313 	if ((r = sshbuf_get_u32(msg, &num)) != 0)
    314 		goto out;
    315 	if (num > MAX_AGENT_IDENTITIES) {
    316 		r = SSH_ERR_INVALID_FORMAT;
    317 		goto out;
    318 	}
    319 	if (num == 0) {
    320 		r = SSH_ERR_AGENT_NO_IDENTITIES;
    321 		goto out;
    322 	}
    323 
    324 	/* Deserialise the response into a list of keys/comments */
    325 	if ((idl = calloc(1, sizeof(*idl))) == NULL ||
    326 	    (idl->keys = calloc(num, sizeof(*idl->keys))) == NULL ||
    327 	    (idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) {
    328 		r = SSH_ERR_ALLOC_FAIL;
    329 		goto out;
    330 	}
    331 	for (i = 0; i < num;) {
    332 		switch (version) {
    333 		case 1:
    334 #ifdef WITH_SSH1
    335 			if ((r = deserialise_identity1(msg,
    336 			    &(idl->keys[i]), &(idl->comments[i]))) != 0)
    337 				goto out;
    338 #endif
    339 			break;
    340 		case 2:
    341 			if ((r = deserialise_identity2(msg,
    342 			    &(idl->keys[i]), &(idl->comments[i]))) != 0) {
    343 				if (r == SSH_ERR_KEY_TYPE_UNKNOWN) {
    344 					/* Gracefully skip unknown key types */
    345 					num--;
    346 					continue;
    347 				} else
    348 					goto out;
    349 			}
    350 			break;
    351 		}
    352 		i++;
    353 	}
    354 	idl->nkeys = num;
    355 	*idlp = idl;
    356 	idl = NULL;
    357 	r = 0;
    358  out:
    359 	sshbuf_free(msg);
    360 	if (idl != NULL)
    361 		ssh_free_identitylist(idl);
    362 	return r;
    363 }
    364 
    365 void
    366 ssh_free_identitylist(struct ssh_identitylist *idl)
    367 {
    368 	size_t i;
    369 
    370 	if (idl == NULL)
    371 		return;
    372 	for (i = 0; i < idl->nkeys; i++) {
    373 		if (idl->keys != NULL)
    374 			sshkey_free(idl->keys[i]);
    375 		if (idl->comments != NULL)
    376 			free(idl->comments[i]);
    377 	}
    378 	free(idl);
    379 }
    380 
    381 /*
    382  * Sends a challenge (typically from a server via ssh(1)) to the agent,
    383  * and waits for a response from the agent.
    384  * Returns true (non-zero) if the agent gave the correct answer, zero
    385  * otherwise.
    386  */
    387 
    388 #ifdef WITH_SSH1
    389 int
    390 ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge,
    391     u_char session_id[16], u_char response[16])
    392 {
    393 	struct sshbuf *msg;
    394 	int r;
    395 	u_char type;
    396 
    397 	if (key->type != KEY_RSA1)
    398 		return SSH_ERR_INVALID_ARGUMENT;
    399 	if ((msg = sshbuf_new()) == NULL)
    400 		return SSH_ERR_ALLOC_FAIL;
    401 	if ((r = sshbuf_put_u8(msg, SSH_AGENTC_RSA_CHALLENGE)) != 0 ||
    402 	    (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 ||
    403 	    (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 ||
    404 	    (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0 ||
    405 	    (r = sshbuf_put_bignum1(msg, challenge)) != 0 ||
    406 	    (r = sshbuf_put(msg, session_id, 16)) != 0 ||
    407 	    (r = sshbuf_put_u32(msg, 1)) != 0) /* Response type for proto 1.1 */
    408 		goto out;
    409 	if ((r = ssh_request_reply(sock, msg, msg)) != 0)
    410 		goto out;
    411 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
    412 		goto out;
    413 	if (agent_failed(type)) {
    414 		r = SSH_ERR_AGENT_FAILURE;
    415 		goto out;
    416 	} else if (type != SSH_AGENT_RSA_RESPONSE) {
    417 		r = SSH_ERR_INVALID_FORMAT;
    418 		goto out;
    419 	}
    420 	if ((r = sshbuf_get(msg, response, 16)) != 0)
    421 		goto out;
    422 	r = 0;
    423  out:
    424 	sshbuf_free(msg);
    425 	return r;
    426 }
    427 #endif
    428 
    429 /* encode signature algoritm in flag bits, so we can keep the msg format */
    430 static u_int
    431 agent_encode_alg(struct sshkey *key, const char *alg)
    432 {
    433 	if (alg != NULL && key->type == KEY_RSA) {
    434 		if (strcmp(alg, "rsa-sha2-256") == 0)
    435 			return SSH_AGENT_RSA_SHA2_256;
    436 		else if (strcmp(alg, "rsa-sha2-512") == 0)
    437 			return SSH_AGENT_RSA_SHA2_512;
    438 	}
    439 	return 0;
    440 }
    441 
    442 /* ask agent to sign data, returns err.h code on error, 0 on success */
    443 int
    444 ssh_agent_sign(int sock, struct sshkey *key,
    445     u_char **sigp, size_t *lenp,
    446     const u_char *data, size_t datalen, const char *alg, u_int compat)
    447 {
    448 	struct sshbuf *msg;
    449 	u_char *blob = NULL, type;
    450 	size_t blen = 0, len = 0;
    451 	u_int flags = 0;
    452 	int r = SSH_ERR_INTERNAL_ERROR;
    453 
    454 	*sigp = NULL;
    455 	*lenp = 0;
    456 
    457 	if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
    458 		return SSH_ERR_INVALID_ARGUMENT;
    459 	if (compat & SSH_BUG_SIGBLOB)
    460 		flags |= SSH_AGENT_OLD_SIGNATURE;
    461 	if ((msg = sshbuf_new()) == NULL)
    462 		return SSH_ERR_ALLOC_FAIL;
    463 	if ((r = sshkey_to_blob(key, &blob, &blen)) != 0)
    464 		goto out;
    465 	flags |= agent_encode_alg(key, alg);
    466 	if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
    467 	    (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
    468 	    (r = sshbuf_put_string(msg, data, datalen)) != 0 ||
    469 	    (r = sshbuf_put_u32(msg, flags)) != 0)
    470 		goto out;
    471 	if ((r = ssh_request_reply(sock, msg, msg)) != 0)
    472 		goto out;
    473 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
    474 		goto out;
    475 	if (agent_failed(type)) {
    476 		r = SSH_ERR_AGENT_FAILURE;
    477 		goto out;
    478 	} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
    479 		r = SSH_ERR_INVALID_FORMAT;
    480 		goto out;
    481 	}
    482 	if ((r = sshbuf_get_string(msg, sigp, &len)) != 0)
    483 		goto out;
    484 	*lenp = len;
    485 	r = 0;
    486  out:
    487 	if (blob != NULL) {
    488 		explicit_bzero(blob, blen);
    489 		free(blob);
    490 	}
    491 	sshbuf_free(msg);
    492 	return r;
    493 }
    494 
    495 /* Encode key for a message to the agent. */
    496 
    497 #ifdef WITH_SSH1
    498 static int
    499 ssh_encode_identity_rsa1(struct sshbuf *b, RSA *key, const char *comment)
    500 {
    501 	int r;
    502 
    503 	/* To keep within the protocol: p < q for ssh. in SSL p > q */
    504 	if ((r = sshbuf_put_u32(b, BN_num_bits(key->n))) != 0 ||
    505 	    (r = sshbuf_put_bignum1(b, key->n)) != 0 ||
    506 	    (r = sshbuf_put_bignum1(b, key->e)) != 0 ||
    507 	    (r = sshbuf_put_bignum1(b, key->d)) != 0 ||
    508 	    (r = sshbuf_put_bignum1(b, key->iqmp)) != 0 ||
    509 	    (r = sshbuf_put_bignum1(b, key->q)) != 0 ||
    510 	    (r = sshbuf_put_bignum1(b, key->p)) != 0 ||
    511 	    (r = sshbuf_put_cstring(b, comment)) != 0)
    512 		return r;
    513 	return 0;
    514 }
    515 #endif
    516 
    517 static int
    518 ssh_encode_identity_ssh2(struct sshbuf *b, struct sshkey *key,
    519     const char *comment)
    520 {
    521 	int r;
    522 
    523 	if ((r = sshkey_private_serialize(key, b)) != 0 ||
    524 	    (r = sshbuf_put_cstring(b, comment)) != 0)
    525 		return r;
    526 	return 0;
    527 }
    528 
    529 static int
    530 encode_constraints(struct sshbuf *m, u_int life, u_int confirm)
    531 {
    532 	int r;
    533 
    534 	if (life != 0) {
    535 		if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_LIFETIME)) != 0 ||
    536 		    (r = sshbuf_put_u32(m, life)) != 0)
    537 			goto out;
    538 	}
    539 	if (confirm != 0) {
    540 		if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0)
    541 			goto out;
    542 	}
    543 	r = 0;
    544  out:
    545 	return r;
    546 }
    547 
    548 /*
    549  * Adds an identity to the authentication server.
    550  * This call is intended only for use by ssh-add(1) and like applications.
    551  */
    552 int
    553 ssh_add_identity_constrained(int sock, struct sshkey *key, const char *comment,
    554     u_int life, u_int confirm)
    555 {
    556 	struct sshbuf *msg;
    557 	int r, constrained = (life || confirm);
    558 	u_char type;
    559 
    560 	if ((msg = sshbuf_new()) == NULL)
    561 		return SSH_ERR_ALLOC_FAIL;
    562 
    563 	switch (key->type) {
    564 #ifdef WITH_SSH1
    565 	case KEY_RSA1:
    566 		type = constrained ?
    567 		    SSH_AGENTC_ADD_RSA_ID_CONSTRAINED :
    568 		    SSH_AGENTC_ADD_RSA_IDENTITY;
    569 		if ((r = sshbuf_put_u8(msg, type)) != 0 ||
    570 		    (r = ssh_encode_identity_rsa1(msg, key->rsa, comment)) != 0)
    571 			goto out;
    572 		break;
    573 #endif
    574 #ifdef WITH_OPENSSL
    575 	case KEY_RSA:
    576 	case KEY_RSA_CERT:
    577 	case KEY_DSA:
    578 	case KEY_DSA_CERT:
    579 	case KEY_ECDSA:
    580 	case KEY_ECDSA_CERT:
    581 #endif
    582 	case KEY_ED25519:
    583 	case KEY_ED25519_CERT:
    584 		type = constrained ?
    585 		    SSH2_AGENTC_ADD_ID_CONSTRAINED :
    586 		    SSH2_AGENTC_ADD_IDENTITY;
    587 		if ((r = sshbuf_put_u8(msg, type)) != 0 ||
    588 		    (r = ssh_encode_identity_ssh2(msg, key, comment)) != 0)
    589 			goto out;
    590 		break;
    591 	default:
    592 		r = SSH_ERR_INVALID_ARGUMENT;
    593 		goto out;
    594 	}
    595 	if (constrained &&
    596 	    (r = encode_constraints(msg, life, confirm)) != 0)
    597 		goto out;
    598 	if ((r = ssh_request_reply(sock, msg, msg)) != 0)
    599 		goto out;
    600 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
    601 		goto out;
    602 	r = decode_reply(type);
    603  out:
    604 	sshbuf_free(msg);
    605 	return r;
    606 }
    607 
    608 /*
    609  * Removes an identity from the authentication server.
    610  * This call is intended only for use by ssh-add(1) and like applications.
    611  */
    612 int
    613 ssh_remove_identity(int sock, struct sshkey *key)
    614 {
    615 	struct sshbuf *msg;
    616 	int r;
    617 	u_char type, *blob = NULL;
    618 	size_t blen;
    619 
    620 	if ((msg = sshbuf_new()) == NULL)
    621 		return SSH_ERR_ALLOC_FAIL;
    622 
    623 #ifdef WITH_SSH1
    624 	if (key->type == KEY_RSA1) {
    625 		if ((r = sshbuf_put_u8(msg,
    626 		    SSH_AGENTC_REMOVE_RSA_IDENTITY)) != 0 ||
    627 		    (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 ||
    628 		    (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 ||
    629 		    (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0)
    630 			goto out;
    631 	} else
    632 #endif
    633 	if (key->type != KEY_UNSPEC) {
    634 		if ((r = sshkey_to_blob(key, &blob, &blen)) != 0)
    635 			goto out;
    636 		if ((r = sshbuf_put_u8(msg,
    637 		    SSH2_AGENTC_REMOVE_IDENTITY)) != 0 ||
    638 		    (r = sshbuf_put_string(msg, blob, blen)) != 0)
    639 			goto out;
    640 	} else {
    641 		r = SSH_ERR_INVALID_ARGUMENT;
    642 		goto out;
    643 	}
    644 	if ((r = ssh_request_reply(sock, msg, msg)) != 0)
    645 		goto out;
    646 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
    647 		goto out;
    648 	r = decode_reply(type);
    649  out:
    650 	if (blob != NULL) {
    651 		explicit_bzero(blob, blen);
    652 		free(blob);
    653 	}
    654 	sshbuf_free(msg);
    655 	return r;
    656 }
    657 
    658 /*
    659  * Add/remove an token-based identity from the authentication server.
    660  * This call is intended only for use by ssh-add(1) and like applications.
    661  */
    662 int
    663 ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
    664     u_int life, u_int confirm)
    665 {
    666 	struct sshbuf *msg;
    667 	int r, constrained = (life || confirm);
    668 	u_char type;
    669 
    670 	if (add) {
    671 		type = constrained ?
    672 		    SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED :
    673 		    SSH_AGENTC_ADD_SMARTCARD_KEY;
    674 	} else
    675 		type = SSH_AGENTC_REMOVE_SMARTCARD_KEY;
    676 
    677 	if ((msg = sshbuf_new()) == NULL)
    678 		return SSH_ERR_ALLOC_FAIL;
    679 	if ((r = sshbuf_put_u8(msg, type)) != 0 ||
    680 	    (r = sshbuf_put_cstring(msg, reader_id)) != 0 ||
    681 	    (r = sshbuf_put_cstring(msg, pin)) != 0)
    682 		goto out;
    683 	if (constrained &&
    684 	    (r = encode_constraints(msg, life, confirm)) != 0)
    685 		goto out;
    686 	if ((r = ssh_request_reply(sock, msg, msg)) != 0)
    687 		goto out;
    688 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
    689 		goto out;
    690 	r = decode_reply(type);
    691  out:
    692 	sshbuf_free(msg);
    693 	return r;
    694 }
    695 
    696 /*
    697  * Removes all identities from the agent.
    698  * This call is intended only for use by ssh-add(1) and like applications.
    699  */
    700 int
    701 ssh_remove_all_identities(int sock, int version)
    702 {
    703 	struct sshbuf *msg;
    704 	u_char type = (version == 1) ?
    705 	    SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
    706 	    SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
    707 	int r;
    708 
    709 	if ((msg = sshbuf_new()) == NULL)
    710 		return SSH_ERR_ALLOC_FAIL;
    711 	if ((r = sshbuf_put_u8(msg, type)) != 0)
    712 		goto out;
    713 	if ((r = ssh_request_reply(sock, msg, msg)) != 0)
    714 		goto out;
    715 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
    716 		goto out;
    717 	r = decode_reply(type);
    718  out:
    719 	sshbuf_free(msg);
    720 	return r;
    721 }
    722