mirror of
https://github.com/openssh/libopenssh
synced 2026-04-17 02:06:45 +00:00
refactor agent client code
removed fatal() buffer_ => sshbuf_ changed lookup of identies to return a fully-deserialised list of keys removed AuthenticationConnection abstration; all operations now use plain socket
This commit is contained in:
894
ssh/authfd.c
894
ssh/authfd.c
File diff suppressed because it is too large
Load Diff
57
ssh/authfd.h
57
ssh/authfd.h
@@ -16,6 +16,33 @@
|
||||
#ifndef AUTHFD_H
|
||||
#define AUTHFD_H
|
||||
|
||||
/* List of identities returned by ssh_fetch_identitylist() */
|
||||
struct ssh_identitylist {
|
||||
size_t nkeys;
|
||||
struct sshkey **keys;
|
||||
char **comments;
|
||||
};
|
||||
|
||||
int ssh_get_authentication_socket(int *fdp);
|
||||
void ssh_close_authentication_socket(int sock);
|
||||
|
||||
int ssh_lock_agent(int sock, int lock, const char *password);
|
||||
int ssh_fetch_identitylist(int sock, int version,
|
||||
struct ssh_identitylist **idlp);
|
||||
void ssh_free_identitylist(struct ssh_identitylist *idl);
|
||||
int ssh_add_identity_constrained(int sock, struct sshkey *key,
|
||||
const char *comment, u_int life, u_int confirm);
|
||||
int ssh_remove_identity(int sock, struct sshkey *key);
|
||||
int ssh_update_card(int sock, int add, const char *reader_id,
|
||||
const char *pin, u_int life, u_int confirm);
|
||||
int ssh_remove_all_identities(int sock, int version);
|
||||
|
||||
int ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge,
|
||||
u_char session_id[16], u_char response[16]);
|
||||
int ssh_agent_sign(int sock, struct sshkey *key,
|
||||
u_char **sigp, u_int *lenp,
|
||||
u_char *data, u_int datalen, u_int compat);
|
||||
|
||||
/* Messages for the authentication agent connection. */
|
||||
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
|
||||
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
|
||||
@@ -60,34 +87,4 @@
|
||||
|
||||
#define SSH_AGENT_OLD_SIGNATURE 0x01
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
Buffer identities;
|
||||
int howmany;
|
||||
} AuthenticationConnection;
|
||||
|
||||
int ssh_agent_present(void);
|
||||
int ssh_get_authentication_socket(void);
|
||||
void ssh_close_authentication_socket(int);
|
||||
|
||||
AuthenticationConnection *ssh_get_authentication_connection(void);
|
||||
void ssh_close_authentication_connection(AuthenticationConnection *);
|
||||
int ssh_get_num_identities(AuthenticationConnection *, int);
|
||||
struct sshkey *ssh_get_first_identity(AuthenticationConnection *, char **, int);
|
||||
struct sshkey *ssh_get_next_identity(AuthenticationConnection *, char **, int);
|
||||
int ssh_add_identity_constrained(AuthenticationConnection *,
|
||||
struct sshkey *, const char *, u_int, u_int);
|
||||
int ssh_remove_identity(AuthenticationConnection *, struct sshkey *);
|
||||
int ssh_remove_all_identities(AuthenticationConnection *, int);
|
||||
int ssh_lock_agent(AuthenticationConnection *, int, const char *);
|
||||
int ssh_update_card(AuthenticationConnection *, int, const char *,
|
||||
const char *, u_int, u_int);
|
||||
|
||||
int ssh_decrypt_challenge(AuthenticationConnection *, struct sshkey *,
|
||||
BIGNUM *, u_char[16], u_int, u_char[16]);
|
||||
|
||||
int
|
||||
ssh_agent_sign(AuthenticationConnection *, struct sshkey *,
|
||||
u_char **, u_int *, u_char *, u_int, u_int);
|
||||
|
||||
#endif /* AUTHFD_H */
|
||||
|
||||
@@ -1705,7 +1705,7 @@ static int
|
||||
client_input_agent_open(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
int remote_id, sock;
|
||||
int remote_id, sock, r;
|
||||
|
||||
/* Read the remote channel number from the message. */
|
||||
remote_id = ssh_packet_get_int(ssh);
|
||||
@@ -1715,7 +1715,10 @@ client_input_agent_open(int type, u_int32_t seq, struct ssh *ssh)
|
||||
* Get a connection to the local authentication agent (this may again
|
||||
* get forwarded).
|
||||
*/
|
||||
sock = ssh_get_authentication_socket();
|
||||
if ((r = ssh_get_authentication_socket(&sock)) != 0 &&
|
||||
r != SSH_ERR_AGENT_NOT_PRESENT)
|
||||
debug("%s: ssh_get_authentication_socket: %s",
|
||||
__func__, ssh_err(r));
|
||||
|
||||
/*
|
||||
* If we could not connect the agent, send an error message back to
|
||||
@@ -1723,7 +1726,7 @@ client_input_agent_open(int type, u_int32_t seq, struct ssh *ssh)
|
||||
* because authentication forwarding is only enabled if we have an
|
||||
* agent.
|
||||
*/
|
||||
if (sock >= 0) {
|
||||
if (r == 0) {
|
||||
c = channel_new("", SSH_CHANNEL_OPEN, sock, sock,
|
||||
-1, 0, 0, 0, "authentication agent connection", 1);
|
||||
c->remote_id = remote_id;
|
||||
@@ -1814,7 +1817,7 @@ static Channel *
|
||||
client_request_agent(struct ssh *ssh, const char *request_type, int rchan)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
int sock;
|
||||
int r, sock;
|
||||
|
||||
if (!options.forward_agent) {
|
||||
error("Warning: ssh server tried agent forwarding.");
|
||||
@@ -1822,9 +1825,12 @@ client_request_agent(struct ssh *ssh, const char *request_type, int rchan)
|
||||
"malicious server.");
|
||||
return NULL;
|
||||
}
|
||||
sock = ssh_get_authentication_socket();
|
||||
if (sock < 0)
|
||||
if ((r = ssh_get_authentication_socket(&sock)) != 0) {
|
||||
if (r != SSH_ERR_AGENT_NOT_PRESENT)
|
||||
debug("%s: ssh_get_authentication_socket: %s",
|
||||
__func__, ssh_err(r));
|
||||
return NULL;
|
||||
}
|
||||
c = channel_new("authentication agent connection",
|
||||
SSH_CHANNEL_OPEN, sock, sock, -1,
|
||||
CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
|
||||
|
||||
@@ -115,6 +115,10 @@ ssh_err(int n)
|
||||
return "certificate does not match key";
|
||||
case SSH_ERR_KEY_NOT_FOUND:
|
||||
return "key not found";
|
||||
case SSH_ERR_AGENT_NOT_PRESENT:
|
||||
return "agent not present";
|
||||
case SSH_ERR_AGENT_NO_IDENTITIES:
|
||||
return "agent contains no identities";
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
|
||||
@@ -67,6 +67,8 @@
|
||||
#define SSH_ERR_KEY_BAD_PERMISSIONS -43
|
||||
#define SSH_ERR_KEY_CERT_MISMATCH -44
|
||||
#define SSH_ERR_KEY_NOT_FOUND -45
|
||||
#define SSH_ERR_AGENT_NOT_PRESENT -46
|
||||
#define SSH_ERR_AGENT_NO_IDENTITIES -47
|
||||
|
||||
|
||||
/* Translate a numeric error code to a human-readable error string */
|
||||
|
||||
141
ssh/ssh-add.c
141
ssh/ssh-add.c
@@ -91,7 +91,7 @@ clear_pass(void)
|
||||
}
|
||||
|
||||
static int
|
||||
delete_file(AuthenticationConnection *ac, const char *filename)
|
||||
delete_file(int agent_fd, const char *filename)
|
||||
{
|
||||
struct sshkey *public;
|
||||
char *comment = NULL;
|
||||
@@ -101,11 +101,12 @@ delete_file(AuthenticationConnection *ac, const char *filename)
|
||||
printf("Bad key file %s: %s\n", filename, ssh_err(r));
|
||||
return -1;
|
||||
}
|
||||
if (ssh_remove_identity(ac, public)) {
|
||||
if ((r = ssh_remove_identity(agent_fd, public)) == 0) {
|
||||
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
|
||||
ret = 0;
|
||||
} else
|
||||
fprintf(stderr, "Could not remove identity: %s\n", filename);
|
||||
fprintf(stderr, "Could not remove identity \"%s\": %s\n",
|
||||
filename, ssh_err(r));
|
||||
|
||||
sshkey_free(public);
|
||||
xfree(comment);
|
||||
@@ -115,14 +116,15 @@ delete_file(AuthenticationConnection *ac, const char *filename)
|
||||
|
||||
/* Send a request to remove all identities. */
|
||||
static int
|
||||
delete_all(AuthenticationConnection *ac)
|
||||
delete_all(int agent_fd)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (ssh_remove_all_identities(ac, 1))
|
||||
if (ssh_remove_all_identities(agent_fd, 1) == 0)
|
||||
ret = 0;
|
||||
/* ignore error-code for ssh2 */
|
||||
ssh_remove_all_identities(ac, 2);
|
||||
/* XXX revisit */
|
||||
ssh_remove_all_identities(agent_fd, 2);
|
||||
|
||||
if (ret == 0)
|
||||
fprintf(stderr, "All identities removed.\n");
|
||||
@@ -133,7 +135,7 @@ delete_all(AuthenticationConnection *ac)
|
||||
}
|
||||
|
||||
static int
|
||||
add_file(AuthenticationConnection *ac, const char *filename, int key_only)
|
||||
add_file(int agent_fd, const char *filename, int key_only)
|
||||
{
|
||||
struct sshkey *private, *cert;
|
||||
char *comment = NULL;
|
||||
@@ -219,8 +221,8 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
|
||||
}
|
||||
buffer_free(&keyblob);
|
||||
|
||||
if (ssh_add_identity_constrained(ac, private, comment, lifetime,
|
||||
confirm)) {
|
||||
if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
|
||||
lifetime, confirm)) == 0) {
|
||||
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
|
||||
ret = 0;
|
||||
if (lifetime != 0)
|
||||
@@ -230,7 +232,8 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
|
||||
fprintf(stderr,
|
||||
"The user must confirm each use of the key\n");
|
||||
} else {
|
||||
fprintf(stderr, "Could not add identity: %s\n", filename);
|
||||
fprintf(stderr, "Could not add identity \"%s\": %s\n",
|
||||
filename, ssh_err(r));
|
||||
}
|
||||
|
||||
/* Skip trying to load the cert if requested */
|
||||
@@ -266,10 +269,11 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
|
||||
}
|
||||
sshkey_free(cert);
|
||||
|
||||
if (!ssh_add_identity_constrained(ac, private, comment,
|
||||
lifetime, confirm)) {
|
||||
error("Certificate %s (%s) add failed", certpath,
|
||||
private->cert->key_id);
|
||||
if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
|
||||
lifetime, confirm)) != 0) {
|
||||
error("Certificate %s (%s) add failed: %s", certpath,
|
||||
private->cert->key_id, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
fprintf(stderr, "Certificate added: %s (%s)\n", certpath,
|
||||
private->cert->key_id);
|
||||
@@ -287,22 +291,23 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
|
||||
}
|
||||
|
||||
static int
|
||||
update_card(AuthenticationConnection *ac, int add, const char *id)
|
||||
update_card(int agent_fd, int add, const char *id)
|
||||
{
|
||||
char *pin;
|
||||
int ret = -1;
|
||||
int r, ret = -1;
|
||||
|
||||
pin = read_passphrase("Enter passphrase for PKCS#11: ", RP_ALLOW_STDIN);
|
||||
if (pin == NULL)
|
||||
return -1;
|
||||
|
||||
if (ssh_update_card(ac, add, id, pin, lifetime, confirm)) {
|
||||
if ((r = ssh_update_card(agent_fd, add, id, pin, lifetime,
|
||||
confirm)) == 0) {
|
||||
fprintf(stderr, "Card %s: %s\n",
|
||||
add ? "added" : "removed", id);
|
||||
ret = 0;
|
||||
} else {
|
||||
fprintf(stderr, "Could not %s card: %s\n",
|
||||
add ? "add" : "remove", id);
|
||||
fprintf(stderr, "Could not %s card \"%s\": %s\n",
|
||||
add ? "add" : "remove", id, ssh_err(r));
|
||||
ret = -1;
|
||||
}
|
||||
xfree(pin);
|
||||
@@ -310,33 +315,42 @@ update_card(AuthenticationConnection *ac, int add, const char *id)
|
||||
}
|
||||
|
||||
static int
|
||||
list_identities(AuthenticationConnection *ac, int do_fp)
|
||||
list_identities(int agent_fd, int do_fp)
|
||||
{
|
||||
struct sshkey *key;
|
||||
char *comment, *fp;
|
||||
char *fp;
|
||||
int version, r, had_identities = 0;
|
||||
struct ssh_identitylist *idlist;
|
||||
size_t i;
|
||||
|
||||
for (version = 1; version <= 2; version++) {
|
||||
for (key = ssh_get_first_identity(ac, &comment, version);
|
||||
key != NULL;
|
||||
key = ssh_get_next_identity(ac, &comment, version)) {
|
||||
if ((r = ssh_fetch_identitylist(agent_fd, version,
|
||||
&idlist)) != 0) {
|
||||
if (r != SSH_ERR_AGENT_NO_IDENTITIES)
|
||||
fprintf(stderr, "error fetching identities for "
|
||||
"protocol %d: %s\n", version, ssh_err(r));
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < idlist->nkeys; i++) {
|
||||
had_identities = 1;
|
||||
if (do_fp) {
|
||||
fp = sshkey_fingerprint(key, SSH_FP_MD5,
|
||||
SSH_FP_HEX);
|
||||
fp = sshkey_fingerprint(idlist->keys[i],
|
||||
SSH_FP_MD5, SSH_FP_HEX);
|
||||
printf("%d %s %s (%s)\n",
|
||||
sshkey_size(key), fp, comment,
|
||||
sshkey_type(key));
|
||||
sshkey_size(idlist->keys[i]), fp,
|
||||
idlist->comments[i],
|
||||
sshkey_type(idlist->keys[i]));
|
||||
xfree(fp);
|
||||
} else {
|
||||
if ((r = sshkey_write(key, stdout)) != 0)
|
||||
fprintf(stderr, "sshkey_write: %s",
|
||||
if ((r = sshkey_write(idlist->keys[i],
|
||||
stdout)) != 0) {
|
||||
fprintf(stderr, "sshkey_write: %s\n",
|
||||
ssh_err(r));
|
||||
fprintf(stdout, " %s\n", comment);
|
||||
continue;
|
||||
}
|
||||
fprintf(stdout, " %s\n", idlist->comments[i]);
|
||||
}
|
||||
sshkey_free(key);
|
||||
xfree(comment);
|
||||
}
|
||||
ssh_free_identitylist(idlist);
|
||||
}
|
||||
if (!had_identities) {
|
||||
printf("The agent has no identities.\n");
|
||||
@@ -346,10 +360,10 @@ list_identities(AuthenticationConnection *ac, int do_fp)
|
||||
}
|
||||
|
||||
static int
|
||||
lock_agent(AuthenticationConnection *ac, int lock)
|
||||
lock_agent(int agent_fd, int lock)
|
||||
{
|
||||
char prompt[100], *p1, *p2;
|
||||
int passok = 1, ret = -1;
|
||||
int r, passok = 1, ret = -1;
|
||||
|
||||
strlcpy(prompt, "Enter lock password: ", sizeof(prompt));
|
||||
p1 = read_passphrase(prompt, RP_ALLOW_STDIN);
|
||||
@@ -363,24 +377,28 @@ lock_agent(AuthenticationConnection *ac, int lock)
|
||||
memset(p2, 0, strlen(p2));
|
||||
xfree(p2);
|
||||
}
|
||||
if (passok && ssh_lock_agent(ac, lock, p1)) {
|
||||
fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un");
|
||||
ret = 0;
|
||||
} else
|
||||
fprintf(stderr, "Failed to %slock agent.\n", lock ? "" : "un");
|
||||
if (passok) {
|
||||
if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) {
|
||||
fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un");
|
||||
ret = 0;
|
||||
} else {
|
||||
fprintf(stderr, "Failed to %slock agent: %sn",
|
||||
lock ? "" : "un", ssh_err(r));
|
||||
}
|
||||
}
|
||||
memset(p1, 0, strlen(p1));
|
||||
xfree(p1);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
do_file(AuthenticationConnection *ac, int deleting, int key_only, char *file)
|
||||
do_file(int agent_fd, int deleting, int key_only, char *file)
|
||||
{
|
||||
if (deleting) {
|
||||
if (delete_file(ac, file) == -1)
|
||||
if (delete_file(agent_fd, file) == -1)
|
||||
return -1;
|
||||
} else {
|
||||
if (add_file(ac, file, key_only) == -1)
|
||||
if (add_file(agent_fd, file, key_only) == -1)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -409,22 +427,28 @@ main(int argc, char **argv)
|
||||
{
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
AuthenticationConnection *ac = NULL;
|
||||
int agent_fd;
|
||||
char *pkcs11provider = NULL;
|
||||
int i, ch, deleting = 0, ret = 0, key_only = 0;
|
||||
int r, i, ch, deleting = 0, ret = 0, key_only = 0;
|
||||
|
||||
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
|
||||
sanitise_stdfd();
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
/* At first, get a connection to the authentication agent. */
|
||||
ac = ssh_get_authentication_connection();
|
||||
if (ac == NULL) {
|
||||
fprintf(stderr,
|
||||
"Could not open a connection to your authentication agent.\n");
|
||||
/* First, get a connection to the authentication agent. */
|
||||
switch (r = ssh_get_authentication_socket(&agent_fd)) {
|
||||
case 0:
|
||||
break;
|
||||
case SSH_ERR_AGENT_NOT_PRESENT:
|
||||
fprintf(stderr, "Could not open a connection to your "
|
||||
"authentication agent.\n");
|
||||
exit(2);
|
||||
default:
|
||||
fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
while ((ch = getopt(argc, argv, "klLcdDxXe:s:t:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'k':
|
||||
@@ -432,12 +456,12 @@ main(int argc, char **argv)
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
if (list_identities(ac, ch == 'l' ? 1 : 0) == -1)
|
||||
if (list_identities(agent_fd, ch == 'l' ? 1 : 0) == -1)
|
||||
ret = 1;
|
||||
goto done;
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (lock_agent(ac, ch == 'x' ? 1 : 0) == -1)
|
||||
if (lock_agent(agent_fd, ch == 'x' ? 1 : 0) == -1)
|
||||
ret = 1;
|
||||
goto done;
|
||||
case 'c':
|
||||
@@ -447,7 +471,7 @@ main(int argc, char **argv)
|
||||
deleting = 1;
|
||||
break;
|
||||
case 'D':
|
||||
if (delete_all(ac) == -1)
|
||||
if (delete_all(agent_fd) == -1)
|
||||
ret = 1;
|
||||
goto done;
|
||||
case 's':
|
||||
@@ -473,7 +497,7 @@ main(int argc, char **argv)
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (pkcs11provider != NULL) {
|
||||
if (update_card(ac, !deleting, pkcs11provider) == -1)
|
||||
if (update_card(agent_fd, !deleting, pkcs11provider) == -1)
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
@@ -495,7 +519,7 @@ main(int argc, char **argv)
|
||||
default_files[i]);
|
||||
if (stat(buf, &st) < 0)
|
||||
continue;
|
||||
if (do_file(ac, deleting, key_only, buf) == -1)
|
||||
if (do_file(agent_fd, deleting, key_only, buf) == -1)
|
||||
ret = 1;
|
||||
else
|
||||
count++;
|
||||
@@ -504,13 +528,14 @@ main(int argc, char **argv)
|
||||
ret = 1;
|
||||
} else {
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (do_file(ac, deleting, key_only, argv[i]) == -1)
|
||||
if (do_file(agent_fd, deleting, key_only,
|
||||
argv[i]) == -1)
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
clear_pass();
|
||||
|
||||
done:
|
||||
ssh_close_authentication_connection(ac);
|
||||
ssh_close_authentication_socket(agent_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1129,10 +1129,16 @@ ssh_init_forwarding(struct ssh *ssh)
|
||||
static void
|
||||
check_agent_present(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (options.forward_agent) {
|
||||
/* Clear agent forwarding if we don't have an agent. */
|
||||
if (!ssh_agent_present())
|
||||
if ((r = ssh_get_authentication_socket(NULL)) != 0) {
|
||||
options.forward_agent = 0;
|
||||
if (r != SSH_ERR_AGENT_NOT_PRESENT)
|
||||
debug("ssh_get_authentication_socket: %s",
|
||||
ssh_err(r));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,33 +61,41 @@ extern char *__progname;
|
||||
static int
|
||||
try_agent_authentication(void)
|
||||
{
|
||||
int type;
|
||||
char *comment;
|
||||
AuthenticationConnection *auth;
|
||||
int r, type, agent_fd, ret = 0;
|
||||
u_char response[16];
|
||||
u_int i;
|
||||
struct sshkey *key;
|
||||
size_t i;
|
||||
BIGNUM *challenge;
|
||||
struct ssh_identitylist *idlist = NULL;
|
||||
|
||||
/* Get connection to the agent. */
|
||||
auth = ssh_get_authentication_connection();
|
||||
if (!auth)
|
||||
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
|
||||
if (r != SSH_ERR_AGENT_NOT_PRESENT)
|
||||
debug("%s: ssh_get_authentication_socket: %s",
|
||||
__func__, ssh_err(r));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((challenge = BN_new()) == NULL)
|
||||
fatal("try_agent_authentication: BN_new failed");
|
||||
|
||||
/* Loop through identities served by the agent. */
|
||||
for (key = ssh_get_first_identity(auth, &comment, 1);
|
||||
key != NULL;
|
||||
key = ssh_get_next_identity(auth, &comment, 1)) {
|
||||
|
||||
if ((r = ssh_fetch_identitylist(agent_fd, 1, &idlist)) != 0) {
|
||||
if (r != SSH_ERR_AGENT_NO_IDENTITIES)
|
||||
debug("%s: ssh_fetch_identitylist: %s",
|
||||
__func__, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < idlist->nkeys; i++) {
|
||||
/* Try this identity. */
|
||||
debug("Trying RSA authentication via agent with '%.100s'", comment);
|
||||
xfree(comment);
|
||||
debug("Trying RSA authentication via agent with '%.100s'",
|
||||
idlist->comments[i]);
|
||||
|
||||
/* Tell the server that we are willing to authenticate using this key. */
|
||||
/*
|
||||
* Tell the server that we are willing to authenticate
|
||||
* using this key.
|
||||
*/
|
||||
packet_start(SSH_CMSG_AUTH_RSA);
|
||||
packet_put_bignum(key->rsa->n);
|
||||
packet_put_bignum(idlist->keys[i]->rsa->n);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
@@ -98,7 +106,6 @@ try_agent_authentication(void)
|
||||
does not support RSA authentication. */
|
||||
if (type == SSH_SMSG_FAILURE) {
|
||||
debug("Server refused our key.");
|
||||
sshkey_free(key);
|
||||
continue;
|
||||
}
|
||||
/* Otherwise it should have sent a challenge. */
|
||||
@@ -112,16 +119,17 @@ try_agent_authentication(void)
|
||||
debug("Received RSA challenge from server.");
|
||||
|
||||
/* Ask the agent to decrypt the challenge. */
|
||||
if (!ssh_decrypt_challenge(auth, key, challenge, session_id, 1, response)) {
|
||||
if ((r = ssh_decrypt_challenge(agent_fd, idlist->keys[i],
|
||||
challenge, session_id, response)) != 0) {
|
||||
/*
|
||||
* The agent failed to authenticate this identifier
|
||||
* although it advertised it supports this. Just
|
||||
* return a wrong value.
|
||||
*/
|
||||
logit("Authentication agent failed to decrypt challenge.");
|
||||
logit("Authentication agent failed to decrypt i"
|
||||
"challenge.");
|
||||
memset(response, 0, sizeof(response));
|
||||
}
|
||||
sshkey_free(key);
|
||||
debug("Sending response to RSA challenge.");
|
||||
|
||||
/* Send the decrypted challenge back to the server. */
|
||||
@@ -134,22 +142,26 @@ try_agent_authentication(void)
|
||||
/* Wait for response from the server. */
|
||||
type = packet_read();
|
||||
|
||||
/* The server returns success if it accepted the authentication. */
|
||||
/*
|
||||
* The server returns success if it accepted the
|
||||
* authentication.
|
||||
*/
|
||||
if (type == SSH_SMSG_SUCCESS) {
|
||||
ssh_close_authentication_connection(auth);
|
||||
BN_clear_free(challenge);
|
||||
debug("RSA authentication accepted by server.");
|
||||
return 1;
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
/* Otherwise it should return failure. */
|
||||
if (type != SSH_SMSG_FAILURE)
|
||||
packet_disconnect("Protocol error waiting RSA auth response: %d",
|
||||
type);
|
||||
packet_disconnect("Protocol error waiting RSA auth "
|
||||
"response: %d", type);
|
||||
}
|
||||
ssh_close_authentication_connection(auth);
|
||||
BN_clear_free(challenge);
|
||||
debug("RSA authentication using agent refused.");
|
||||
return 0;
|
||||
out:
|
||||
ssh_free_identitylist(idlist);
|
||||
ssh_close_authentication_socket(agent_fd);
|
||||
BN_clear_free(challenge);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -236,7 +236,7 @@ typedef struct idlist Idlist;
|
||||
|
||||
struct identity {
|
||||
TAILQ_ENTRY(identity) next;
|
||||
AuthenticationConnection *ac; /* set if agent supports key */
|
||||
int agent_fd; /* >=0 if agent supports key */
|
||||
struct sshkey *key; /* public/private key */
|
||||
char *filename; /* comment for agent-only keys */
|
||||
int tried;
|
||||
@@ -255,7 +255,7 @@ struct Authctxt {
|
||||
int attempt;
|
||||
/* pubkey */
|
||||
Idlist keys;
|
||||
AuthenticationConnection *agent;
|
||||
int agent_fd;
|
||||
/* hostbased */
|
||||
Sensitive *sensitive;
|
||||
/* kbd-interactive */
|
||||
@@ -1200,9 +1200,9 @@ identity_sign(Identity *id, u_char **sigp, u_int *lenp,
|
||||
int ret;
|
||||
|
||||
/* the agent supports this key */
|
||||
if (id->ac)
|
||||
return (ssh_agent_sign(id->ac, id->key, sigp, lenp,
|
||||
data, datalen, compat));
|
||||
if (id->agent_fd)
|
||||
return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp,
|
||||
data, datalen, compat);
|
||||
/*
|
||||
* we have already loaded the private key or
|
||||
* the private key is stored in external hardware
|
||||
@@ -1414,9 +1414,9 @@ pubkey_prepare(struct ssh *ssh)
|
||||
Identity *id;
|
||||
Idlist agent, files, *preferred;
|
||||
struct sshkey *key;
|
||||
AuthenticationConnection *ac;
|
||||
char *comment;
|
||||
int i, found;
|
||||
int agent_fd, i, r, found;
|
||||
size_t j;
|
||||
struct ssh_identitylist *idlist;
|
||||
|
||||
TAILQ_INIT(&agent); /* keys from the agent */
|
||||
TAILQ_INIT(&files); /* keys from the config file */
|
||||
@@ -1437,37 +1437,48 @@ pubkey_prepare(struct ssh *ssh)
|
||||
TAILQ_INSERT_TAIL(&files, id, next);
|
||||
}
|
||||
/* list of keys supported by the agent */
|
||||
if ((ac = ssh_get_authentication_connection())) {
|
||||
for (key = ssh_get_first_identity(ac, &comment, 2);
|
||||
key != NULL;
|
||||
key = ssh_get_next_identity(ac, &comment, 2)) {
|
||||
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
|
||||
if (r != SSH_ERR_AGENT_NOT_PRESENT)
|
||||
debug("%s: ssh_get_authentication_socket: %s",
|
||||
__func__, ssh_err(r));
|
||||
} else if ((r = ssh_fetch_identitylist(agent_fd, 2, &idlist)) != 0) {
|
||||
if (r != SSH_ERR_AGENT_NO_IDENTITIES)
|
||||
debug("%s: ssh_fetch_identitylist: %s",
|
||||
__func__, ssh_err(r));
|
||||
} else {
|
||||
for (j = 0; j < idlist->nkeys; j++) {
|
||||
found = 0;
|
||||
TAILQ_FOREACH(id, &files, next) {
|
||||
/* agent keys from the config file are preferred */
|
||||
if (sshkey_equal(key, id->key)) {
|
||||
sshkey_free(key);
|
||||
xfree(comment);
|
||||
/*
|
||||
* agent keys from the config file are
|
||||
* preferred
|
||||
*/
|
||||
if (sshkey_equal(idlist->keys[j], id->key)) {
|
||||
TAILQ_REMOVE(&files, id, next);
|
||||
TAILQ_INSERT_TAIL(preferred, id, next);
|
||||
id->ac = ac;
|
||||
id->agent_fd = agent_fd;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found && !options.identities_only) {
|
||||
id = xcalloc(1, sizeof(*id));
|
||||
id->key = key;
|
||||
id->filename = comment;
|
||||
id->ac = ac;
|
||||
/* XXX "steals" key/comment from idlist */
|
||||
id->key = idlist->keys[j];
|
||||
id->filename = idlist->comments[j];
|
||||
idlist->keys[j] = NULL;
|
||||
idlist->comments[j] = NULL;
|
||||
id->agent_fd = agent_fd;
|
||||
TAILQ_INSERT_TAIL(&agent, id, next);
|
||||
}
|
||||
}
|
||||
ssh_free_identitylist(idlist);
|
||||
/* append remaining agent keys */
|
||||
for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) {
|
||||
TAILQ_REMOVE(&agent, id, next);
|
||||
TAILQ_INSERT_TAIL(preferred, id, next);
|
||||
}
|
||||
authctxt->agent = ac;
|
||||
authctxt->agent_fd = agent_fd;
|
||||
}
|
||||
/* append remaining keys from the config file */
|
||||
for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) {
|
||||
@@ -1485,8 +1496,8 @@ pubkey_cleanup(struct ssh *ssh)
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
Identity *id;
|
||||
|
||||
if (authctxt->agent != NULL)
|
||||
ssh_close_authentication_connection(authctxt->agent);
|
||||
if (authctxt->agent_fd != -1)
|
||||
ssh_close_authentication_socket(authctxt->agent_fd);
|
||||
for (id = TAILQ_FIRST(&authctxt->keys); id;
|
||||
id = TAILQ_FIRST(&authctxt->keys)) {
|
||||
TAILQ_REMOVE(&authctxt->keys, id, next);
|
||||
|
||||
Reference in New Issue
Block a user