1263970Sdes/* $OpenBSD: authfd.c,v 1.92 2014/01/31 16:39:19 tedu Exp $ */ 257429Smarkm/* 357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 557429Smarkm * All rights reserved 665674Skris * Functions for connecting the local authentication agent. 760576Skris * 865674Skris * As far as I am concerned, the code I have written for this software 965674Skris * can be used freely for any purpose. Any derived versions of this 1065674Skris * software must be clearly marked as such, and if the derived work is 1165674Skris * incompatible with the protocol description in the RFC file, it must be 1265674Skris * called by a name other than "ssh" or "Secure Shell". 1360576Skris * 1465674Skris * SSH2 implementation, 1565674Skris * Copyright (c) 2000 Markus Friedl. All rights reserved. 1660576Skris * 1765674Skris * Redistribution and use in source and binary forms, with or without 1865674Skris * modification, are permitted provided that the following conditions 1965674Skris * are met: 2065674Skris * 1. Redistributions of source code must retain the above copyright 2165674Skris * notice, this list of conditions and the following disclaimer. 2265674Skris * 2. Redistributions in binary form must reproduce the above copyright 2365674Skris * notice, this list of conditions and the following disclaimer in the 2465674Skris * documentation and/or other materials provided with the distribution. 2565674Skris * 2665674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2765674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2865674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2965674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3065674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3165674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3265674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3365674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3465674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3565674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3657429Smarkm */ 3757429Smarkm 3857429Smarkm#include "includes.h" 3957429Smarkm 40162856Sdes#include <sys/types.h> 41162856Sdes#include <sys/un.h> 42162856Sdes#include <sys/socket.h> 43162856Sdes 4476262Sgreen#include <openssl/evp.h> 45263970Sdes#include <openssl/crypto.h> 4676262Sgreen 47162856Sdes#include <fcntl.h> 48162856Sdes#include <stdlib.h> 49162856Sdes#include <signal.h> 50162856Sdes#include <stdarg.h> 51162856Sdes#include <string.h> 52162856Sdes#include <unistd.h> 53162856Sdes 54162856Sdes#include "xmalloc.h" 5557429Smarkm#include "ssh.h" 5657429Smarkm#include "rsa.h" 5757429Smarkm#include "buffer.h" 5865674Skris#include "key.h" 5965674Skris#include "authfd.h" 6076262Sgreen#include "cipher.h" 6165674Skris#include "kex.h" 6269591Sgreen#include "compat.h" 6376262Sgreen#include "log.h" 6476262Sgreen#include "atomicio.h" 65162856Sdes#include "misc.h" 6657429Smarkm 67106130Sdesstatic int agent_present = 0; 68106130Sdes 6965674Skris/* helper */ 7065674Skrisint decode_reply(int type); 7165674Skris 7269591Sgreen/* macro to check for "agent failure" message */ 7369591Sgreen#define agent_failed(x) \ 7492559Sdes ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \ 7598684Sdes (x == SSH2_AGENT_FAILURE)) 7669591Sgreen 77106130Sdesint 78106130Sdesssh_agent_present(void) 79106130Sdes{ 80106130Sdes int authfd; 81106130Sdes 82106130Sdes if (agent_present) 83106130Sdes return 1; 84106130Sdes if ((authfd = ssh_get_authentication_socket()) == -1) 85106130Sdes return 0; 86106130Sdes else { 87106130Sdes ssh_close_authentication_socket(authfd); 88106130Sdes return 1; 89106130Sdes } 90106130Sdes} 91106130Sdes 9257429Smarkm/* Returns the number of the authentication fd, or -1 if there is none. */ 9357429Smarkm 9457429Smarkmint 9576262Sgreenssh_get_authentication_socket(void) 9657429Smarkm{ 9757429Smarkm const char *authsocket; 9892559Sdes int sock; 9957429Smarkm struct sockaddr_un sunaddr; 10057429Smarkm 10157429Smarkm authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); 10257429Smarkm if (!authsocket) 10357429Smarkm return -1; 10457429Smarkm 105263970Sdes memset(&sunaddr, 0, sizeof(sunaddr)); 10657429Smarkm sunaddr.sun_family = AF_UNIX; 10757429Smarkm strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); 10857429Smarkm 10957429Smarkm sock = socket(AF_UNIX, SOCK_STREAM, 0); 11057429Smarkm if (sock < 0) 11157429Smarkm return -1; 11257429Smarkm 11357429Smarkm /* close on exec */ 114247485Sdes if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { 11557429Smarkm close(sock); 11657429Smarkm return -1; 11757429Smarkm } 118162856Sdes if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { 11957429Smarkm close(sock); 12057429Smarkm return -1; 12157429Smarkm } 122106130Sdes agent_present = 1; 12357429Smarkm return sock; 12457429Smarkm} 12557429Smarkm 12692559Sdesstatic int 12765674Skrisssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply) 12865674Skris{ 129149753Sdes u_int l, len; 13065674Skris char buf[1024]; 13165674Skris 13265674Skris /* Get the length of the message, and format it in the buffer. */ 13365674Skris len = buffer_len(request); 134162856Sdes put_u32(buf, len); 13565674Skris 13665674Skris /* Send the length and then the packet to the agent. */ 137124211Sdes if (atomicio(vwrite, auth->fd, buf, 4) != 4 || 138124211Sdes atomicio(vwrite, auth->fd, buffer_ptr(request), 13965674Skris buffer_len(request)) != buffer_len(request)) { 14065674Skris error("Error writing to authentication socket."); 14165674Skris return 0; 14265674Skris } 14365674Skris /* 14465674Skris * Wait for response from the agent. First read the length of the 14565674Skris * response packet. 14665674Skris */ 147137019Sdes if (atomicio(read, auth->fd, buf, 4) != 4) { 148137019Sdes error("Error reading response length from authentication socket."); 149137019Sdes return 0; 15065674Skris } 15165674Skris 15265674Skris /* Extract the length, and check it for sanity. */ 153162856Sdes len = get_u32(buf); 15465674Skris if (len > 256 * 1024) 155126277Sdes fatal("Authentication response too long: %u", len); 15665674Skris 15765674Skris /* Read the rest of the response in to the buffer. */ 15865674Skris buffer_clear(reply); 15965674Skris while (len > 0) { 16065674Skris l = len; 16165674Skris if (l > sizeof(buf)) 16265674Skris l = sizeof(buf); 163149753Sdes if (atomicio(read, auth->fd, buf, l) != l) { 16465674Skris error("Error reading response from authentication socket."); 16565674Skris return 0; 16665674Skris } 16799063Sdes buffer_append(reply, buf, l); 16865674Skris len -= l; 16965674Skris } 17065674Skris return 1; 17165674Skris} 17265674Skris 17357429Smarkm/* 17457429Smarkm * Closes the agent socket if it should be closed (depends on how it was 17557429Smarkm * obtained). The argument must have been returned by 17657429Smarkm * ssh_get_authentication_socket(). 17757429Smarkm */ 17857429Smarkm 17960576Skrisvoid 18057429Smarkmssh_close_authentication_socket(int sock) 18157429Smarkm{ 18257429Smarkm if (getenv(SSH_AUTHSOCKET_ENV_NAME)) 18357429Smarkm close(sock); 18457429Smarkm} 18557429Smarkm 18657429Smarkm/* 18757429Smarkm * Opens and connects a private socket for communication with the 18857429Smarkm * authentication agent. Returns the file descriptor (which must be 18957429Smarkm * shut down and closed by the caller when no longer needed). 19057429Smarkm * Returns NULL if an error occurred and the connection could not be 19157429Smarkm * opened. 19257429Smarkm */ 19357429Smarkm 19457429SmarkmAuthenticationConnection * 19576262Sgreenssh_get_authentication_connection(void) 19657429Smarkm{ 19757429Smarkm AuthenticationConnection *auth; 19857429Smarkm int sock; 19957429Smarkm 20057429Smarkm sock = ssh_get_authentication_socket(); 20157429Smarkm 20257429Smarkm /* 20357429Smarkm * Fail if we couldn't obtain a connection. This happens if we 20457429Smarkm * exited due to a timeout. 20557429Smarkm */ 20657429Smarkm if (sock < 0) 20757429Smarkm return NULL; 20857429Smarkm 209263970Sdes auth = xcalloc(1, sizeof(*auth)); 21057429Smarkm auth->fd = sock; 21157429Smarkm buffer_init(&auth->identities); 21257429Smarkm auth->howmany = 0; 21357429Smarkm 21457429Smarkm return auth; 21557429Smarkm} 21657429Smarkm 21757429Smarkm/* 21857429Smarkm * Closes the connection to the authentication agent and frees any associated 21957429Smarkm * memory. 22057429Smarkm */ 22157429Smarkm 22260576Skrisvoid 22365674Skrisssh_close_authentication_connection(AuthenticationConnection *auth) 22457429Smarkm{ 22565674Skris buffer_free(&auth->identities); 22665674Skris close(auth->fd); 227263970Sdes free(auth); 22857429Smarkm} 22957429Smarkm 23098684Sdes/* Lock/unlock agent */ 23198684Sdesint 23298684Sdesssh_lock_agent(AuthenticationConnection *auth, int lock, const char *password) 23398684Sdes{ 23498684Sdes int type; 23598684Sdes Buffer msg; 23698684Sdes 23798684Sdes buffer_init(&msg); 23898684Sdes buffer_put_char(&msg, lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK); 23998684Sdes buffer_put_cstring(&msg, password); 24098684Sdes 24198684Sdes if (ssh_request_reply(auth, &msg, &msg) == 0) { 24298684Sdes buffer_free(&msg); 24398684Sdes return 0; 24498684Sdes } 24598684Sdes type = buffer_get_char(&msg); 24698684Sdes buffer_free(&msg); 24798684Sdes return decode_reply(type); 24898684Sdes} 24998684Sdes 25057429Smarkm/* 25157429Smarkm * Returns the first authentication identity held by the agent. 25257429Smarkm */ 25357429Smarkm 25476262Sgreenint 25576262Sgreenssh_get_num_identities(AuthenticationConnection *auth, int version) 25657429Smarkm{ 25765674Skris int type, code1 = 0, code2 = 0; 25865674Skris Buffer request; 25957429Smarkm 26092559Sdes switch (version) { 26165674Skris case 1: 26265674Skris code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; 26365674Skris code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER; 26465674Skris break; 26565674Skris case 2: 26665674Skris code1 = SSH2_AGENTC_REQUEST_IDENTITIES; 26765674Skris code2 = SSH2_AGENT_IDENTITIES_ANSWER; 26865674Skris break; 26965674Skris default: 27076262Sgreen return 0; 27165674Skris } 27265674Skris 27357429Smarkm /* 27457429Smarkm * Send a message to the agent requesting for a list of the 27557429Smarkm * identities it can represent. 27657429Smarkm */ 27765674Skris buffer_init(&request); 27865674Skris buffer_put_char(&request, code1); 27957429Smarkm 28057429Smarkm buffer_clear(&auth->identities); 28165674Skris if (ssh_request_reply(auth, &request, &auth->identities) == 0) { 28265674Skris buffer_free(&request); 28376262Sgreen return 0; 28457429Smarkm } 28565674Skris buffer_free(&request); 28657429Smarkm 28757429Smarkm /* Get message type, and verify that we got a proper answer. */ 28865674Skris type = buffer_get_char(&auth->identities); 28969591Sgreen if (agent_failed(type)) { 29076262Sgreen return 0; 29165674Skris } else if (type != code2) { 29265674Skris fatal("Bad authentication reply message type: %d", type); 29365674Skris } 29457429Smarkm 29557429Smarkm /* Get the number of entries in the response and check it for sanity. */ 29657429Smarkm auth->howmany = buffer_get_int(&auth->identities); 297126277Sdes if ((u_int)auth->howmany > 1024) 29876262Sgreen fatal("Too many identities in authentication reply: %d", 29965674Skris auth->howmany); 30057429Smarkm 30176262Sgreen return auth->howmany; 30257429Smarkm} 30357429Smarkm 30465674SkrisKey * 30576262Sgreenssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version) 30676262Sgreen{ 30776262Sgreen /* get number of identities and return the first entry (if any). */ 30876262Sgreen if (ssh_get_num_identities(auth, version) > 0) 30976262Sgreen return ssh_get_next_identity(auth, comment, version); 31076262Sgreen return NULL; 31176262Sgreen} 31276262Sgreen 31376262SgreenKey * 31465674Skrisssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version) 31557429Smarkm{ 316149753Sdes int keybits; 31776262Sgreen u_int bits; 31876262Sgreen u_char *blob; 31976262Sgreen u_int blen; 32065674Skris Key *key = NULL; 32157429Smarkm 32257429Smarkm /* Return failure if no more entries. */ 32357429Smarkm if (auth->howmany <= 0) 32465674Skris return NULL; 32557429Smarkm 32657429Smarkm /* 32757429Smarkm * Get the next entry from the packet. These will abort with a fatal 32857429Smarkm * error if the packet is too short or contains corrupt data. 32957429Smarkm */ 33092559Sdes switch (version) { 33165674Skris case 1: 33276262Sgreen key = key_new(KEY_RSA1); 33365674Skris bits = buffer_get_int(&auth->identities); 33465674Skris buffer_get_bignum(&auth->identities, key->rsa->e); 33565674Skris buffer_get_bignum(&auth->identities, key->rsa->n); 33665674Skris *comment = buffer_get_string(&auth->identities, NULL); 337149753Sdes keybits = BN_num_bits(key->rsa->n); 338149753Sdes if (keybits < 0 || bits != (u_int)keybits) 339124211Sdes logit("Warning: identity keysize mismatch: actual %d, announced %u", 34065674Skris BN_num_bits(key->rsa->n), bits); 34165674Skris break; 34265674Skris case 2: 34365674Skris blob = buffer_get_string(&auth->identities, &blen); 34465674Skris *comment = buffer_get_string(&auth->identities, NULL); 34576262Sgreen key = key_from_blob(blob, blen); 346263970Sdes free(blob); 34765674Skris break; 34865674Skris default: 34965674Skris return NULL; 35065674Skris } 35157429Smarkm /* Decrement the number of remaining entries. */ 35257429Smarkm auth->howmany--; 35365674Skris return key; 35457429Smarkm} 35557429Smarkm 35657429Smarkm/* 35757429Smarkm * Generates a random challenge, sends it to the agent, and waits for 35857429Smarkm * response from the agent. Returns true (non-zero) if the agent gave the 35957429Smarkm * correct answer, zero otherwise. Response type selects the style of 36057429Smarkm * response desired, with 0 corresponding to protocol version 1.0 (no longer 36157429Smarkm * supported) and 1 corresponding to protocol version 1.1. 36257429Smarkm */ 36357429Smarkm 36457429Smarkmint 36557429Smarkmssh_decrypt_challenge(AuthenticationConnection *auth, 36665674Skris Key* key, BIGNUM *challenge, 36776262Sgreen u_char session_id[16], 36876262Sgreen u_int response_type, 36976262Sgreen u_char response[16]) 37057429Smarkm{ 37157429Smarkm Buffer buffer; 37265674Skris int success = 0; 37365674Skris int i; 37465674Skris int type; 37557429Smarkm 37676262Sgreen if (key->type != KEY_RSA1) 37765674Skris return 0; 37865674Skris if (response_type == 0) { 379124211Sdes logit("Compatibility with ssh protocol version 1.0 no longer supported."); 38065674Skris return 0; 38165674Skris } 38257429Smarkm buffer_init(&buffer); 38365674Skris buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE); 38465674Skris buffer_put_int(&buffer, BN_num_bits(key->rsa->n)); 38565674Skris buffer_put_bignum(&buffer, key->rsa->e); 38665674Skris buffer_put_bignum(&buffer, key->rsa->n); 38757429Smarkm buffer_put_bignum(&buffer, challenge); 38892559Sdes buffer_append(&buffer, session_id, 16); 38957429Smarkm buffer_put_int(&buffer, response_type); 39057429Smarkm 39165674Skris if (ssh_request_reply(auth, &buffer, &buffer) == 0) { 39257429Smarkm buffer_free(&buffer); 39357429Smarkm return 0; 39457429Smarkm } 39565674Skris type = buffer_get_char(&buffer); 39665674Skris 39769591Sgreen if (agent_failed(type)) { 398124211Sdes logit("Agent admitted failure to authenticate using the key."); 39965674Skris } else if (type != SSH_AGENT_RSA_RESPONSE) { 40065674Skris fatal("Bad authentication response: %d", type); 40165674Skris } else { 40265674Skris success = 1; 40365674Skris /* 40465674Skris * Get the response from the packet. This will abort with a 40565674Skris * fatal error if the packet is corrupt. 40665674Skris */ 40765674Skris for (i = 0; i < 16; i++) 408162856Sdes response[i] = (u_char)buffer_get_char(&buffer); 40957429Smarkm } 41065674Skris buffer_free(&buffer); 41165674Skris return success; 41265674Skris} 41357429Smarkm 41465674Skris/* ask agent to sign data, returns -1 on error, 0 on success */ 41565674Skrisint 41665674Skrisssh_agent_sign(AuthenticationConnection *auth, 41765674Skris Key *key, 41892559Sdes u_char **sigp, u_int *lenp, 41992559Sdes u_char *data, u_int datalen) 42065674Skris{ 42169591Sgreen extern int datafellows; 42265674Skris Buffer msg; 42376262Sgreen u_char *blob; 42476262Sgreen u_int blen; 42569591Sgreen int type, flags = 0; 42665674Skris int ret = -1; 42757429Smarkm 42876262Sgreen if (key_to_blob(key, &blob, &blen) == 0) 42965674Skris return -1; 43057429Smarkm 43169591Sgreen if (datafellows & SSH_BUG_SIGBLOB) 43269591Sgreen flags = SSH_AGENT_OLD_SIGNATURE; 43369591Sgreen 43465674Skris buffer_init(&msg); 43565674Skris buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); 43665674Skris buffer_put_string(&msg, blob, blen); 43765674Skris buffer_put_string(&msg, data, datalen); 43869591Sgreen buffer_put_int(&msg, flags); 439263970Sdes free(blob); 44057429Smarkm 44165674Skris if (ssh_request_reply(auth, &msg, &msg) == 0) { 44265674Skris buffer_free(&msg); 44365674Skris return -1; 44457429Smarkm } 44565674Skris type = buffer_get_char(&msg); 44669591Sgreen if (agent_failed(type)) { 447124211Sdes logit("Agent admitted failure to sign using the key."); 44865674Skris } else if (type != SSH2_AGENT_SIGN_RESPONSE) { 44965674Skris fatal("Bad authentication response: %d", type); 45065674Skris } else { 45165674Skris ret = 0; 45265674Skris *sigp = buffer_get_string(&msg, lenp); 45365674Skris } 45465674Skris buffer_free(&msg); 45565674Skris return ret; 45665674Skris} 45757429Smarkm 45865674Skris/* Encode key for a message to the agent. */ 45957429Smarkm 46092559Sdesstatic void 46176262Sgreenssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment) 46265674Skris{ 46365674Skris buffer_put_int(b, BN_num_bits(key->n)); 46465674Skris buffer_put_bignum(b, key->n); 46565674Skris buffer_put_bignum(b, key->e); 46665674Skris buffer_put_bignum(b, key->d); 46765674Skris /* To keep within the protocol: p < q for ssh. in SSL p > q */ 46865674Skris buffer_put_bignum(b, key->iqmp); /* ssh key->u */ 46965674Skris buffer_put_bignum(b, key->q); /* ssh key->p, SSL key->q */ 47065674Skris buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */ 47192559Sdes buffer_put_cstring(b, comment); 47265674Skris} 47357429Smarkm 47492559Sdesstatic void 47576262Sgreenssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) 47665674Skris{ 477263970Sdes key_private_serialize(key, b); 47876262Sgreen buffer_put_cstring(b, comment); 47957429Smarkm} 48057429Smarkm 48157429Smarkm/* 48257429Smarkm * Adds an identity to the authentication server. This call is not meant to 48357429Smarkm * be used by normal applications. 48457429Smarkm */ 48557429Smarkm 48660576Skrisint 48798684Sdesssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, 488113911Sdes const char *comment, u_int life, u_int confirm) 48957429Smarkm{ 49065674Skris Buffer msg; 491113911Sdes int type, constrained = (life || confirm); 49257429Smarkm 49365674Skris buffer_init(&msg); 49457429Smarkm 49565674Skris switch (key->type) { 49676262Sgreen case KEY_RSA1: 49798684Sdes type = constrained ? 49898684Sdes SSH_AGENTC_ADD_RSA_ID_CONSTRAINED : 49998684Sdes SSH_AGENTC_ADD_RSA_IDENTITY; 50098684Sdes buffer_put_char(&msg, type); 50176262Sgreen ssh_encode_identity_rsa1(&msg, key->rsa, comment); 50276262Sgreen break; 50365674Skris case KEY_RSA: 504204917Sdes case KEY_RSA_CERT: 505215116Sdes case KEY_RSA_CERT_V00: 50665674Skris case KEY_DSA: 507204917Sdes case KEY_DSA_CERT: 508215116Sdes case KEY_DSA_CERT_V00: 509221420Sdes case KEY_ECDSA: 510221420Sdes case KEY_ECDSA_CERT: 511263970Sdes case KEY_ED25519: 512263970Sdes case KEY_ED25519_CERT: 51398684Sdes type = constrained ? 51498684Sdes SSH2_AGENTC_ADD_ID_CONSTRAINED : 51598684Sdes SSH2_AGENTC_ADD_IDENTITY; 51698684Sdes buffer_put_char(&msg, type); 51776262Sgreen ssh_encode_identity_ssh2(&msg, key, comment); 51865674Skris break; 51965674Skris default: 52065674Skris buffer_free(&msg); 52157429Smarkm return 0; 52257429Smarkm } 52398684Sdes if (constrained) { 52498684Sdes if (life != 0) { 52598684Sdes buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); 52698684Sdes buffer_put_int(&msg, life); 52798684Sdes } 528113911Sdes if (confirm != 0) 529113911Sdes buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM); 53098684Sdes } 53165674Skris if (ssh_request_reply(auth, &msg, &msg) == 0) { 53265674Skris buffer_free(&msg); 53357429Smarkm return 0; 53457429Smarkm } 53565674Skris type = buffer_get_char(&msg); 53665674Skris buffer_free(&msg); 53765674Skris return decode_reply(type); 53857429Smarkm} 53957429Smarkm 54057429Smarkm/* 54157429Smarkm * Removes an identity from the authentication server. This call is not 54257429Smarkm * meant to be used by normal applications. 54357429Smarkm */ 54457429Smarkm 54560576Skrisint 54665674Skrisssh_remove_identity(AuthenticationConnection *auth, Key *key) 54757429Smarkm{ 54865674Skris Buffer msg; 54965674Skris int type; 55076262Sgreen u_char *blob; 55176262Sgreen u_int blen; 55257429Smarkm 55365674Skris buffer_init(&msg); 55457429Smarkm 55576262Sgreen if (key->type == KEY_RSA1) { 55665674Skris buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY); 55765674Skris buffer_put_int(&msg, BN_num_bits(key->rsa->n)); 55865674Skris buffer_put_bignum(&msg, key->rsa->e); 55965674Skris buffer_put_bignum(&msg, key->rsa->n); 560263970Sdes } else if (key->type != KEY_UNSPEC) { 56176262Sgreen key_to_blob(key, &blob, &blen); 56265674Skris buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); 56365674Skris buffer_put_string(&msg, blob, blen); 564263970Sdes free(blob); 56565674Skris } else { 56665674Skris buffer_free(&msg); 56757429Smarkm return 0; 56857429Smarkm } 56965674Skris if (ssh_request_reply(auth, &msg, &msg) == 0) { 57065674Skris buffer_free(&msg); 57157429Smarkm return 0; 57257429Smarkm } 57365674Skris type = buffer_get_char(&msg); 57465674Skris buffer_free(&msg); 57565674Skris return decode_reply(type); 57657429Smarkm} 57757429Smarkm 57892559Sdesint 579126277Sdesssh_update_card(AuthenticationConnection *auth, int add, 580124211Sdes const char *reader_id, const char *pin, u_int life, u_int confirm) 58192559Sdes{ 58292559Sdes Buffer msg; 583124211Sdes int type, constrained = (life || confirm); 58492559Sdes 585124211Sdes if (add) { 586124211Sdes type = constrained ? 587124211Sdes SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED : 588124211Sdes SSH_AGENTC_ADD_SMARTCARD_KEY; 589124211Sdes } else 590124211Sdes type = SSH_AGENTC_REMOVE_SMARTCARD_KEY; 591124211Sdes 59292559Sdes buffer_init(&msg); 593124211Sdes buffer_put_char(&msg, type); 59492559Sdes buffer_put_cstring(&msg, reader_id); 59598684Sdes buffer_put_cstring(&msg, pin); 596126277Sdes 597124211Sdes if (constrained) { 598124211Sdes if (life != 0) { 599124211Sdes buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); 600124211Sdes buffer_put_int(&msg, life); 601124211Sdes } 602124211Sdes if (confirm != 0) 603124211Sdes buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM); 604124211Sdes } 605124211Sdes 60692559Sdes if (ssh_request_reply(auth, &msg, &msg) == 0) { 60792559Sdes buffer_free(&msg); 60892559Sdes return 0; 60992559Sdes } 61092559Sdes type = buffer_get_char(&msg); 61192559Sdes buffer_free(&msg); 61292559Sdes return decode_reply(type); 61392559Sdes} 61492559Sdes 61557429Smarkm/* 61657429Smarkm * Removes all identities from the agent. This call is not meant to be used 61757429Smarkm * by normal applications. 61857429Smarkm */ 61957429Smarkm 62060576Skrisint 62165674Skrisssh_remove_all_identities(AuthenticationConnection *auth, int version) 62257429Smarkm{ 62365674Skris Buffer msg; 62465674Skris int type; 62565674Skris int code = (version==1) ? 62665674Skris SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES : 62765674Skris SSH2_AGENTC_REMOVE_ALL_IDENTITIES; 62857429Smarkm 62965674Skris buffer_init(&msg); 63065674Skris buffer_put_char(&msg, code); 63157429Smarkm 63265674Skris if (ssh_request_reply(auth, &msg, &msg) == 0) { 63365674Skris buffer_free(&msg); 63457429Smarkm return 0; 63557429Smarkm } 63665674Skris type = buffer_get_char(&msg); 63765674Skris buffer_free(&msg); 63865674Skris return decode_reply(type); 63965674Skris} 64057429Smarkm 64176262Sgreenint 64265674Skrisdecode_reply(int type) 64365674Skris{ 64457429Smarkm switch (type) { 64557429Smarkm case SSH_AGENT_FAILURE: 64669591Sgreen case SSH_COM_AGENT2_FAILURE: 64792559Sdes case SSH2_AGENT_FAILURE: 648124211Sdes logit("SSH_AGENT_FAILURE"); 64957429Smarkm return 0; 65057429Smarkm case SSH_AGENT_SUCCESS: 65157429Smarkm return 1; 65257429Smarkm default: 65365674Skris fatal("Bad response from authentication agent: %d", type); 65457429Smarkm } 65557429Smarkm /* NOTREACHED */ 65657429Smarkm return 0; 65757429Smarkm} 658