upstream commit

move authfd.c and its tentacles to the new buffer/key
 API; ok markus@
This commit is contained in:
djm@openbsd.org 2015-01-14 20:05:27 +00:00 committed by Damien Miller
parent 0088c57af3
commit 141efe4954
10 changed files with 850 additions and 686 deletions

846
authfd.c

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfd.h,v 1.37 2009/08/27 17:44:52 djm Exp $ */
/* $OpenBSD: authfd.h,v 1.38 2015/01/14 20:05:27 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -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, size_t *lenp,
const u_char *data, size_t 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,35 +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);
Key *ssh_get_first_identity(AuthenticationConnection *, char **, int);
Key *ssh_get_next_identity(AuthenticationConnection *, char **, int);
int ssh_add_identity_constrained(AuthenticationConnection *, Key *,
const char *, u_int, u_int);
int ssh_remove_identity(AuthenticationConnection *, Key *);
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 *, Key *, BIGNUM *, u_char[16],
u_int, u_char[16]);
int
ssh_agent_sign(AuthenticationConnection *, Key *, u_char **, u_int *, u_char *,
u_int);
#endif /* AUTHFD_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.261 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: clientloop.c,v 1.262 2015/01/14 20:05:27 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -110,6 +110,7 @@
#include "match.h"
#include "msg.h"
#include "roaming.h"
#include "ssherr.h"
/* import options */
extern Options options;
@ -1782,7 +1783,7 @@ static void
client_input_agent_open(int type, u_int32_t seq, void *ctxt)
{
Channel *c = NULL;
int remote_id, sock;
int r, remote_id, sock;
/* Read the remote channel number from the message. */
remote_id = packet_get_int();
@ -1792,7 +1793,11 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt)
* 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
@ -1910,7 +1915,7 @@ static Channel *
client_request_agent(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.");
@ -1918,9 +1923,12 @@ client_request_agent(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,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor.c,v 1.137 2015/01/13 07:39:19 djm Exp $ */
/* $OpenBSD: monitor.c,v 1.138 2015/01/14 20:05:27 djm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@ -101,6 +101,7 @@
#include "roaming.h"
#include "authfd.h"
#include "match.h"
#include "ssherr.h"
#ifdef GSSAPI
static Gssctxt *gsscontext = NULL;
@ -685,28 +686,28 @@ mm_answer_moduli(int sock, Buffer *m)
}
#endif
extern AuthenticationConnection *auth_conn;
int
mm_answer_sign(int sock, Buffer *m)
{
Key *key;
extern int auth_sock; /* XXX move to state struct? */
struct sshkey *key;
u_char *p;
u_char *signature;
u_int siglen, datlen;
int keyid;
size_t datlen, siglen;
int r, keyid;
debug3("%s", __func__);
keyid = buffer_get_int(m);
p = buffer_get_string(m, &datlen);
if ((r = sshbuf_get_u32(m, &keyid)) != 0 ||
(r = sshbuf_get_string(m, &p, &datlen)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
/*
* Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes),
* SHA384 (48 bytes) and SHA512 (64 bytes).
*/
if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64)
fatal("%s: data length incorrect: %u", __func__, datlen);
fatal("%s: data length incorrect: %zu", __func__, datlen);
/* save session id, it will be passed on the first call */
if (session_id2_len == 0) {
@ -716,20 +717,25 @@ mm_answer_sign(int sock, Buffer *m)
}
if ((key = get_hostkey_by_index(keyid)) != NULL) {
if (key_sign(key, &signature, &siglen, p, datlen) < 0)
fatal("%s: key_sign failed", __func__);
if ((r = sshkey_sign(key, &signature, &siglen, p, datlen,
datafellows)) != 0)
fatal("%s: sshkey_sign failed: %s",
__func__, ssh_err(r));
} else if ((key = get_hostkey_public_by_index(keyid)) != NULL &&
auth_conn != NULL) {
if (ssh_agent_sign(auth_conn, key, &signature, &siglen, p,
datlen) < 0)
fatal("%s: ssh_agent_sign failed", __func__);
auth_sock > 0) {
if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen,
p, datlen, datafellows)) != 0) {
fatal("%s: ssh_agent_sign failed: %s",
__func__, ssh_err(r));
}
} else
fatal("%s: no hostkey from index %d", __func__, keyid);
debug3("%s: signature %p(%u)", __func__, signature, siglen);
debug3("%s: signature %p(%zu)", __func__, signature, siglen);
buffer_clear(m);
buffer_put_string(m, signature, siglen);
sshbuf_reset(m);
if ((r = sshbuf_put_string(m, signature, siglen)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
free(p);
free(signature);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: session.c,v 1.275 2014/12/22 07:55:51 djm Exp $ */
/* $OpenBSD: session.c,v 1.276 2015/01/14 20:05:27 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@ -1620,11 +1620,11 @@ launch_login(struct passwd *pw, const char *hostname)
static void
child_close_fds(void)
{
extern AuthenticationConnection *auth_conn;
extern int auth_sock;
if (auth_conn) {
ssh_close_authentication_connection(auth_conn);
auth_conn = NULL;
if (auth_sock != -1) {
close(auth_sock);
auth_sock = -1;
}
if (packet_get_connection_in() == packet_get_connection_out())

259
ssh-add.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-add.c,v 1.115 2014/12/21 22:27:56 djm Exp $ */
/* $OpenBSD: ssh-add.c,v 1.116 2015/01/14 20:05:27 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -44,6 +44,7 @@
#include <openssl/evp.h>
#include "openbsd-compat/openssl-compat.h"
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdarg.h>
@ -56,8 +57,8 @@
#include "ssh.h"
#include "rsa.h"
#include "log.h"
#include "key.h"
#include "buffer.h"
#include "sshkey.h"
#include "sshbuf.h"
#include "authfd.h"
#include "authfile.h"
#include "pathnames.h"
@ -103,22 +104,22 @@ clear_pass(void)
}
static int
delete_file(AuthenticationConnection *ac, const char *filename, int key_only)
delete_file(int agent_fd, const char *filename, int key_only)
{
Key *public = NULL, *cert = NULL;
struct sshkey *public, *cert = NULL;
char *certpath = NULL, *comment = NULL;
int ret = -1;
int r, ret = -1;
public = key_load_public(filename, &comment);
if (public == NULL) {
printf("Bad key file %s\n", filename);
if ((r = sshkey_load_public(filename, &public, &comment)) != 0) {
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));
if (key_only)
goto out;
@ -127,13 +128,13 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only)
free(comment);
comment = NULL;
xasprintf(&certpath, "%s-cert.pub", filename);
if ((cert = key_load_public(certpath, &comment)) == NULL)
if ((r = sshkey_load_public(certpath, &cert, &comment)) == 0)
goto out;
if (!key_equal_public(cert, public))
if (!sshkey_equal_public(cert, public))
fatal("Certificate %s does not match private key %s",
certpath, filename);
if (ssh_remove_identity(ac, cert)) {
if (ssh_remove_identity(agent_fd, cert)) {
fprintf(stderr, "Identity removed: %s (%s)\n", certpath,
comment);
ret = 0;
@ -142,9 +143,9 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only)
out:
if (cert != NULL)
key_free(cert);
sshkey_free(cert);
if (public != NULL)
key_free(public);
sshkey_free(public);
free(certpath);
free(comment);
@ -153,14 +154,15 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only)
/* 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");
@ -171,13 +173,13 @@ 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)
{
Key *private, *cert;
struct sshkey *private, *cert;
char *comment = NULL;
char msg[1024], *certpath = NULL;
int r, fd, perms_ok, ret = -1;
Buffer keyblob;
int r, fd, ret = -1;
struct sshbuf *keyblob;
if (strcmp(filename, "-") == 0) {
fd = STDIN_FILENO;
@ -192,30 +194,38 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
* will occur multiple times, so check perms first and bail if wrong.
*/
if (fd != STDIN_FILENO) {
perms_ok = key_perm_ok(fd, filename);
if (!perms_ok) {
if (sshkey_perm_ok(fd, filename) != 0) {
close(fd);
return -1;
}
}
buffer_init(&keyblob);
if (!key_load_file(fd, filename, &keyblob)) {
buffer_free(&keyblob);
if ((keyblob = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__);
if ((r = sshkey_load_file(fd, keyblob)) != 0) {
fprintf(stderr, "Error loading key \"%s\": %s\n",
filename, ssh_err(r));
sshbuf_free(keyblob);
close(fd);
return -1;
}
close(fd);
/* At first, try empty passphrase */
if ((r = sshkey_parse_private_fileblob(&keyblob, "", filename,
&private, &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE)
fatal("Cannot parse %s: %s", filename, ssh_err(r));
if ((r = sshkey_parse_private_fileblob(keyblob, "", filename,
&private, &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) {
fprintf(stderr, "Error loading key \"%s\": %s\n",
filename, ssh_err(r));
goto fail_load;
}
/* try last */
if (private == NULL && pass != NULL) {
if ((r = sshkey_parse_private_fileblob(&keyblob, pass, filename,
if ((r = sshkey_parse_private_fileblob(keyblob, pass, filename,
&private, &comment)) != 0 &&
r != SSH_ERR_KEY_WRONG_PASSPHRASE)
fatal("Cannot parse %s: %s", filename, ssh_err(r));
r != SSH_ERR_KEY_WRONG_PASSPHRASE) {
fprintf(stderr, "Error loading key \"%s\": %s\n",
filename, ssh_err(r));
goto fail_load;
}
}
if (comment == NULL)
comment = xstrdup(filename);
@ -226,28 +236,30 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
comment);
for (;;) {
pass = read_passphrase(msg, RP_ALLOW_STDIN);
if (strcmp(pass, "") == 0) {
if (strcmp(pass, "") == 0)
goto fail_load;
if ((r = sshkey_parse_private_fileblob(keyblob, pass,
filename, &private, NULL)) == 0)
break;
else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) {
fprintf(stderr,
"Error loading key \"%s\": %s\n",
filename, ssh_err(r));
fail_load:
clear_pass();
free(comment);
buffer_free(&keyblob);
sshbuf_free(keyblob);
return -1;
}
if ((r = sshkey_parse_private_fileblob(&keyblob,
pass, filename, &private, NULL)) != 0 &&
r != SSH_ERR_KEY_WRONG_PASSPHRASE)
fatal("Cannot parse %s: %s",
filename, ssh_err(r));
if (private != NULL)
break;
clear_pass();
snprintf(msg, sizeof msg,
"Bad passphrase, try again for %.200s: ", comment);
}
}
buffer_free(&keyblob);
sshbuf_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)
@ -257,7 +269,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,29 +279,39 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
/* Now try to add the certificate flavour too */
xasprintf(&certpath, "%s-cert.pub", filename);
if ((cert = key_load_public(certpath, NULL)) == NULL)
if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) {
if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT)
error("Failed to load certificate \"%s\": %s",
certpath, ssh_err(r));
goto out;
}
if (!key_equal_public(cert, private)) {
if (!sshkey_equal_public(cert, private)) {
error("Certificate %s does not match private key %s",
certpath, filename);
key_free(cert);
sshkey_free(cert);
goto out;
}
/* Graft with private bits */
if (key_to_certified(private, key_cert_is_legacy(cert)) != 0) {
error("%s: key_to_certified failed", __func__);
key_free(cert);
if ((r = sshkey_to_certified(private,
sshkey_cert_is_legacy(cert))) != 0) {
error("%s: sshkey_to_certified: %s", __func__, ssh_err(r));
sshkey_free(cert);
goto out;
}
key_cert_copy(cert, private);
key_free(cert);
if ((r = sshkey_cert_copy(cert, private)) != 0) {
error("%s: key_cert_copy: %s", __func__, ssh_err(r));
sshkey_free(cert);
goto out;
}
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);
@ -297,19 +320,18 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
if (confirm != 0)
fprintf(stderr, "The user must confirm each use of the key\n");
out:
if (certpath != NULL)
free(certpath);
free(certpath);
free(comment);
key_free(private);
sshkey_free(private);
return ret;
}
static int
update_card(AuthenticationConnection *ac, int add, const char *id)
update_card(int agent_fd, int add, const char *id)
{
char *pin = NULL;
int ret = -1;
int r, ret = -1;
if (add) {
if ((pin = read_passphrase("Enter passphrase for PKCS#11: ",
@ -317,14 +339,14 @@ update_card(AuthenticationConnection *ac, int add, const char *id)
return -1;
}
if (ssh_update_card(ac, add, id, pin == NULL ? "" : pin,
lifetime, confirm)) {
if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : 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;
}
free(pin);
@ -332,32 +354,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)
{
Key *key;
char *comment, *fp;
int had_identities = 0;
int version;
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 = key_fingerprint(key, fingerprint_hash,
SSH_FP_DEFAULT);
fp = sshkey_fingerprint(idlist->keys[i],
fingerprint_hash, SSH_FP_DEFAULT);
printf("%d %s %s (%s)\n",
key_size(key), fp, comment, key_type(key));
sshkey_size(idlist->keys[i]), fp,
idlist->comments[i],
sshkey_type(idlist->keys[i]));
free(fp);
} else {
if (!key_write(key, stdout))
fprintf(stderr, "key_write failed");
fprintf(stdout, " %s\n", comment);
if ((r = sshkey_write(idlist->keys[i],
stdout)) != 0) {
fprintf(stderr, "sshkey_write: %s\n",
ssh_err(r));
continue;
}
fprintf(stdout, " %s\n", idlist->comments[i]);
}
key_free(key);
free(comment);
}
ssh_free_identitylist(idlist);
}
if (!had_identities) {
printf("The agent has no identities.\n");
@ -367,10 +399,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);
@ -384,24 +416,28 @@ lock_agent(AuthenticationConnection *ac, int lock)
explicit_bzero(p2, strlen(p2));
free(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: %s\n",
lock ? "" : "un", ssh_err(r));
}
}
explicit_bzero(p1, strlen(p1));
free(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, key_only) == -1)
if (delete_file(agent_fd, file, key_only) == -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;
@ -431,9 +467,9 @@ 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;
int xflag = 0, lflag = 0, Dflag = 0;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
@ -448,13 +484,19 @@ main(int argc, char **argv)
setvbuf(stdout, NULL, _IOLBF, 0);
/* 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:e:s:t:")) != -1) {
switch (ch) {
case 'E':
@ -510,15 +552,15 @@ main(int argc, char **argv)
if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1)
fatal("Invalid combination of actions");
else if (xflag) {
if (lock_agent(ac, xflag == 'x' ? 1 : 0) == -1)
if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1)
ret = 1;
goto done;
} else if (lflag) {
if (list_identities(ac, lflag == 'l' ? 1 : 0) == -1)
if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1)
ret = 1;
goto done;
} else if (Dflag) {
if (delete_all(ac) == -1)
if (delete_all(agent_fd) == -1)
ret = 1;
goto done;
}
@ -526,7 +568,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;
}
@ -548,7 +590,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++;
@ -557,13 +599,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;
}

11
ssh.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.411 2015/01/08 10:15:45 djm Exp $ */
/* $OpenBSD: ssh.c,v 1.412 2015/01/14 20:05:27 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -107,6 +107,7 @@
#include "uidswap.h"
#include "roaming.h"
#include "version.h"
#include "ssherr.h"
#ifdef ENABLE_PKCS11
#include "ssh-pkcs11.h"
@ -1502,10 +1503,16 @@ ssh_init_forwarding(void)
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));
}
}
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect1.c,v 1.76 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: sshconnect1.c,v 1.77 2015/01/14 20:05:27 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -22,6 +22,7 @@
#include <openssl/bn.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@ -49,6 +50,7 @@
#include "hostfile.h"
#include "auth.h"
#include "digest.h"
#include "ssherr.h"
/* Session id for the current session. */
u_char session_id[16];
@ -64,33 +66,38 @@ 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;
Key *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)) {
/* Loop through identities served by the agent. */
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);
free(comment);
debug("Trying RSA authentication via agent with '%.100s'",
idlist->comments[i]);
/* 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();
@ -101,7 +108,6 @@ try_agent_authentication(void)
does not support RSA authentication. */
if (type == SSH_SMSG_FAILURE) {
debug("Server refused our key.");
key_free(key);
continue;
}
/* Otherwise it should have sent a challenge. */
@ -115,16 +121,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 "
"challenge: %s", ssh_err(r));
explicit_bzero(response, sizeof(response));
}
key_free(key);
debug("Sending response to RSA challenge.");
/* Send the decrypted challenge back to the server. */
@ -137,22 +144,25 @@ 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;
}
/* Otherwise it should return failure. */
if (type != SSH_SMSG_FAILURE)
packet_disconnect("Protocol error waiting RSA auth response: %d",
type);
ret = 1;
break;
} else if (type != SSH_SMSG_FAILURE)
packet_disconnect("Protocol error waiting RSA auth "
"response: %d", type);
}
ssh_close_authentication_connection(auth);
if (ret != 1)
debug("RSA authentication using agent refused.");
out:
ssh_free_identitylist(idlist);
ssh_close_authentication_socket(agent_fd);
BN_clear_free(challenge);
debug("RSA authentication using agent refused.");
return 0;
return ret;
}
/*

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect2.c,v 1.213 2015/01/08 10:14:08 djm Exp $ */
/* $OpenBSD: sshconnect2.c,v 1.214 2015/01/14 20:05:27 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved.
@ -70,6 +70,7 @@
#include "pathnames.h"
#include "uidswap.h"
#include "hostfile.h"
#include "ssherr.h"
#ifdef GSSAPI
#include "ssh-gss.h"
@ -131,10 +132,10 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
} while (0)
while ((alg = strsep(&avail, ",")) && *alg != '\0') {
if ((ktype = key_type_from_name(alg)) == KEY_UNSPEC)
if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC)
fatal("%s: unknown alg %s", __func__, alg);
if (lookup_key_in_hostkeys_by_type(hostkeys,
key_type_plain(ktype), NULL))
sshkey_type_plain(ktype), NULL))
ALG_APPEND(first, alg);
else
ALG_APPEND(last, alg);
@ -242,15 +243,15 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
* Authenticate user
*/
typedef struct Authctxt Authctxt;
typedef struct Authmethod Authmethod;
typedef struct cauthctxt Authctxt;
typedef struct cauthmethod Authmethod;
typedef struct identity Identity;
typedef struct idlist Idlist;
struct identity {
TAILQ_ENTRY(identity) next;
AuthenticationConnection *ac; /* set if agent supports key */
Key *key; /* public/private key */
int agent_fd; /* >=0 if agent supports key */
struct sshkey *key; /* public/private key */
char *filename; /* comment for agent-only keys */
int tried;
int isprivate; /* key points to the private key */
@ -258,17 +259,18 @@ struct identity {
};
TAILQ_HEAD(idlist, identity);
struct Authctxt {
struct cauthctxt {
const char *server_user;
const char *local_user;
const char *host;
const char *service;
Authmethod *method;
struct cauthmethod *method;
sig_atomic_t success;
char *authlist;
int attempt;
/* pubkey */
Idlist keys;
AuthenticationConnection *agent;
struct idlist keys;
int agent_fd;
/* hostbased */
Sensitive *sensitive;
/* kbd-interactive */
@ -276,7 +278,8 @@ struct Authctxt {
/* generic */
void *methoddata;
};
struct Authmethod {
struct cauthmethod {
char *name; /* string to compare against server's list */
int (*userauth)(Authctxt *authctxt);
void (*cleanup)(Authctxt *authctxt);
@ -582,7 +585,7 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
key->type, pktype);
goto done;
}
fp = key_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
debug2("input_userauth_pk_ok: fp %s", fp);
free(fp);
@ -956,27 +959,29 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
}
static int
identity_sign(Identity *id, u_char **sigp, u_int *lenp,
u_char *data, u_int datalen)
identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat)
{
Key *prv;
int ret;
/* the agent supports this key */
if (id->ac)
return (ssh_agent_sign(id->ac, id->key, sigp, lenp,
data, datalen));
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
*/
if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))
return (key_sign(id->key, sigp, lenp, data, datalen));
return (sshkey_sign(id->key, sigp, lenp, data, datalen,
compat));
/* load the private key from the file */
if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL)
return (-1);
ret = key_sign(prv, sigp, lenp, data, datalen);
key_free(prv);
return (-1); /* XXX return decent error code */
ret = sshkey_sign(prv, sigp, lenp, data, datalen, compat);
sshkey_free(prv);
return (ret);
}
@ -985,7 +990,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
{
Buffer b;
u_char *blob, *signature;
u_int bloblen, slen;
u_int bloblen;
size_t slen;
u_int skip = 0;
int ret = -1;
int have_sig = 1;
@ -1026,8 +1032,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
/* generate signature */
ret = identity_sign(id, &signature, &slen,
buffer_ptr(&b), buffer_len(&b));
if (ret == -1) {
buffer_ptr(&b), buffer_len(&b), datafellows);
if (ret != 0) {
free(blob);
buffer_free(&b);
return 0;
@ -1102,7 +1108,7 @@ load_identity_file(char *filename, int userprovided)
{
Key *private;
char prompt[300], *passphrase;
int perm_ok = 0, quit, i;
int r, perm_ok = 0, quit, i;
struct stat st;
if (stat(filename, &st) < 0) {
@ -1110,33 +1116,49 @@ load_identity_file(char *filename, int userprovided)
filename, strerror(errno));
return NULL;
}
private = key_load_private_type(KEY_UNSPEC, filename, "", NULL, &perm_ok);
if (!perm_ok) {
if (private != NULL)
key_free(private);
return NULL;
}
if (private == NULL) {
if (options.batch_mode)
return NULL;
snprintf(prompt, sizeof prompt,
"Enter passphrase for key '%.100s': ", filename);
for (i = 0; i < options.number_of_password_prompts; i++) {
snprintf(prompt, sizeof prompt,
"Enter passphrase for key '%.100s': ", filename);
for (i = 0; i <= options.number_of_password_prompts; i++) {
if (i == 0)
passphrase = "";
else {
passphrase = read_passphrase(prompt, 0);
if (strcmp(passphrase, "") != 0) {
private = key_load_private_type(KEY_UNSPEC,
filename, passphrase, NULL, NULL);
quit = 0;
} else {
if (*passphrase == '\0') {
debug2("no passphrase given, try next key");
quit = 1;
free(passphrase);
break;
}
}
switch ((r = sshkey_load_private_type(KEY_UNSPEC, filename,
passphrase, &private, NULL, &perm_ok))) {
case 0:
break;
case SSH_ERR_KEY_WRONG_PASSPHRASE:
if (options.batch_mode) {
quit = 1;
break;
}
debug2("bad passphrase given, try again...");
break;
case SSH_ERR_SYSTEM_ERROR:
if (errno == ENOENT) {
debug2("Load key \"%s\": %s",
filename, ssh_err(r));
quit = 1;
break;
}
/* FALLTHROUGH */
default:
error("Load key \"%s\": %s", filename, ssh_err(r));
quit = 1;
break;
}
if (i > 0) {
explicit_bzero(passphrase, strlen(passphrase));
free(passphrase);
if (private != NULL || quit)
break;
debug2("bad passphrase given, try again...");
}
if (private != NULL || quit)
break;
}
return private;
}
@ -1150,12 +1172,12 @@ load_identity_file(char *filename, int userprovided)
static void
pubkey_prepare(Authctxt *authctxt)
{
Identity *id, *id2, *tmp;
Idlist agent, files, *preferred;
Key *key;
AuthenticationConnection *ac;
char *comment;
int i, found;
struct identity *id, *id2, *tmp;
struct idlist agent, files, *preferred;
struct sshkey *key;
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 */
@ -1185,7 +1207,7 @@ pubkey_prepare(Authctxt *authctxt)
if (id2->key == NULL ||
(id2->key->flags & SSHKEY_FLAG_EXT) == 0)
continue;
if (key_equal(id->key, id2->key)) {
if (sshkey_equal(id->key, id2->key)) {
TAILQ_REMOVE(&files, id, next);
TAILQ_INSERT_TAIL(preferred, id, next);
found = 1;
@ -1200,37 +1222,48 @@ pubkey_prepare(Authctxt *authctxt)
}
}
/* 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 (key_equal(key, id->key)) {
key_free(key);
free(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)) {
@ -1248,13 +1281,13 @@ pubkey_cleanup(Authctxt *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);
if (id->key)
key_free(id->key);
sshkey_free(id->key);
free(id->filename);
free(id);
}

43
sshd.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshd.c,v 1.431 2015/01/07 18:15:07 tedu Exp $ */
/* $OpenBSD: sshd.c,v 1.432 2015/01/14 20:05:27 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -123,6 +123,7 @@
#include "roaming.h"
#include "ssh-sandbox.h"
#include "version.h"
#include "ssherr.h"
#ifndef O_NOCTTY
#define O_NOCTTY 0
@ -191,7 +192,7 @@ char *server_version_string = NULL;
Kex *xxx_kex;
/* Daemon's agent connection */
AuthenticationConnection *auth_conn = NULL;
int auth_sock = -1;
int have_agent = 0;
/*
@ -655,7 +656,7 @@ privsep_preauth_child(void)
static int
privsep_preauth(Authctxt *authctxt)
{
int status;
int status, r;
pid_t pid;
struct ssh_sandbox *box = NULL;
@ -673,8 +674,14 @@ privsep_preauth(Authctxt *authctxt)
debug2("Network child is on pid %ld", (long)pid);
pmonitor->m_pid = pid;
if (have_agent)
auth_conn = ssh_get_authentication_connection();
if (have_agent) {
r = ssh_get_authentication_socket(&auth_sock);
if (r != 0) {
error("Could not get agent socket: %s",
ssh_err(r));
have_agent = 0;
}
}
if (box != NULL)
ssh_sandbox_parent_preauth(box, pid);
monitor_child_preauth(authctxt, pmonitor);
@ -1397,7 +1404,7 @@ main(int ac, char **av)
{
extern char *optarg;
extern int optind;
int opt, i, j, on = 1;
int r, opt, i, j, on = 1;
int sock_in = -1, sock_out = -1, newsock = -1;
const char *remote_ip;
int remote_port;
@ -1706,7 +1713,7 @@ main(int ac, char **av)
if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME))
setenv(SSH_AUTHSOCKET_ENV_NAME,
options.host_key_agent, 1);
have_agent = ssh_agent_present();
have_agent = ssh_get_authentication_socket(NULL);
}
for (i = 0; i < options.num_host_key_files; i++) {
@ -2103,8 +2110,12 @@ main(int ac, char **av)
if (use_privsep) {
if (privsep_preauth(authctxt) == 1)
goto authenticated;
} else if (compat20 && have_agent)
auth_conn = ssh_get_authentication_connection();
} else if (compat20 && have_agent) {
if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) {
error("Unable to get agent socket: %s", ssh_err(r));
have_agent = -1;
}
}
/* perform the key exchange */
/* authenticate user and start session */
@ -2425,6 +2436,8 @@ void
sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen,
u_char *data, u_int dlen)
{
int r;
if (privkey) {
if (PRIVSEP(key_sign(privkey, signature, slen, data, dlen) < 0))
fatal("%s: key_sign failed", __func__);
@ -2432,9 +2445,15 @@ sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen,
if (mm_key_sign(pubkey, signature, slen, data, dlen) < 0)
fatal("%s: pubkey_sign failed", __func__);
} else {
if (ssh_agent_sign(auth_conn, pubkey, signature, slen, data,
dlen))
fatal("%s: ssh_agent_sign failed", __func__);
size_t xxx_slen;
if ((r = ssh_agent_sign(auth_sock, pubkey, signature, &xxx_slen,
data, dlen, datafellows)) != 0)
fatal("%s: ssh_agent_sign failed: %s",
__func__, ssh_err(r));
/* XXX: Old API is u_int; new size_t */
if (slen != NULL)
*slen = xxx_slen;
}
}