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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -16,6 +16,33 @@
#ifndef AUTHFD_H #ifndef AUTHFD_H
#define 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. */ /* Messages for the authentication agent connection. */
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 #define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2 #define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
@ -60,35 +87,4 @@
#define SSH_AGENT_OLD_SIGNATURE 0x01 #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 */ #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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -110,6 +110,7 @@
#include "match.h" #include "match.h"
#include "msg.h" #include "msg.h"
#include "roaming.h" #include "roaming.h"
#include "ssherr.h"
/* import options */ /* import options */
extern Options options; extern Options options;
@ -1782,7 +1783,7 @@ static void
client_input_agent_open(int type, u_int32_t seq, void *ctxt) client_input_agent_open(int type, u_int32_t seq, void *ctxt)
{ {
Channel *c = NULL; Channel *c = NULL;
int remote_id, sock; int r, remote_id, sock;
/* Read the remote channel number from the message. */ /* Read the remote channel number from the message. */
remote_id = packet_get_int(); 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 a connection to the local authentication agent (this may again
* get forwarded). * 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 * 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) client_request_agent(const char *request_type, int rchan)
{ {
Channel *c = NULL; Channel *c = NULL;
int sock; int r, sock;
if (!options.forward_agent) { if (!options.forward_agent) {
error("Warning: ssh server tried agent forwarding."); error("Warning: ssh server tried agent forwarding.");
@ -1918,9 +1923,12 @@ client_request_agent(const char *request_type, int rchan)
"malicious server."); "malicious server.");
return NULL; return NULL;
} }
sock = ssh_get_authentication_socket(); if ((r = ssh_get_authentication_socket(&sock)) != 0) {
if (sock < 0) if (r != SSH_ERR_AGENT_NOT_PRESENT)
debug("%s: ssh_get_authentication_socket: %s",
__func__, ssh_err(r));
return NULL; return NULL;
}
c = channel_new("authentication agent connection", c = channel_new("authentication agent connection",
SSH_CHANNEL_OPEN, sock, sock, -1, SSH_CHANNEL_OPEN, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, 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 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org> * Copyright 2002 Markus Friedl <markus@openbsd.org>
@ -101,6 +101,7 @@
#include "roaming.h" #include "roaming.h"
#include "authfd.h" #include "authfd.h"
#include "match.h" #include "match.h"
#include "ssherr.h"
#ifdef GSSAPI #ifdef GSSAPI
static Gssctxt *gsscontext = NULL; static Gssctxt *gsscontext = NULL;
@ -685,28 +686,28 @@ mm_answer_moduli(int sock, Buffer *m)
} }
#endif #endif
extern AuthenticationConnection *auth_conn;
int int
mm_answer_sign(int sock, Buffer *m) 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 *p;
u_char *signature; u_char *signature;
u_int siglen, datlen; size_t datlen, siglen;
int keyid; int r, keyid;
debug3("%s", __func__); debug3("%s", __func__);
keyid = buffer_get_int(m); if ((r = sshbuf_get_u32(m, &keyid)) != 0 ||
p = buffer_get_string(m, &datlen); (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), * Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes),
* SHA384 (48 bytes) and SHA512 (64 bytes). * SHA384 (48 bytes) and SHA512 (64 bytes).
*/ */
if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64) 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 */ /* save session id, it will be passed on the first call */
if (session_id2_len == 0) { 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 = get_hostkey_by_index(keyid)) != NULL) {
if (key_sign(key, &signature, &siglen, p, datlen) < 0) if ((r = sshkey_sign(key, &signature, &siglen, p, datlen,
fatal("%s: key_sign failed", __func__); datafellows)) != 0)
fatal("%s: sshkey_sign failed: %s",
__func__, ssh_err(r));
} else if ((key = get_hostkey_public_by_index(keyid)) != NULL && } else if ((key = get_hostkey_public_by_index(keyid)) != NULL &&
auth_conn != NULL) { auth_sock > 0) {
if (ssh_agent_sign(auth_conn, key, &signature, &siglen, p, if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen,
datlen) < 0) p, datlen, datafellows)) != 0) {
fatal("%s: ssh_agent_sign failed", __func__); fatal("%s: ssh_agent_sign failed: %s",
__func__, ssh_err(r));
}
} else } else
fatal("%s: no hostkey from index %d", __func__, keyid); 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); sshbuf_reset(m);
buffer_put_string(m, signature, siglen); if ((r = sshbuf_put_string(m, signature, siglen)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
free(p); free(p);
free(signature); 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 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
@ -1620,11 +1620,11 @@ launch_login(struct passwd *pw, const char *hostname)
static void static void
child_close_fds(void) child_close_fds(void)
{ {
extern AuthenticationConnection *auth_conn; extern int auth_sock;
if (auth_conn) { if (auth_sock != -1) {
ssh_close_authentication_connection(auth_conn); close(auth_sock);
auth_conn = NULL; auth_sock = -1;
} }
if (packet_get_connection_in() == packet_get_connection_out()) 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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -44,6 +44,7 @@
#include <openssl/evp.h> #include <openssl/evp.h>
#include "openbsd-compat/openssl-compat.h" #include "openbsd-compat/openssl-compat.h"
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <pwd.h> #include <pwd.h>
#include <stdarg.h> #include <stdarg.h>
@ -56,8 +57,8 @@
#include "ssh.h" #include "ssh.h"
#include "rsa.h" #include "rsa.h"
#include "log.h" #include "log.h"
#include "key.h" #include "sshkey.h"
#include "buffer.h" #include "sshbuf.h"
#include "authfd.h" #include "authfd.h"
#include "authfile.h" #include "authfile.h"
#include "pathnames.h" #include "pathnames.h"
@ -103,22 +104,22 @@ clear_pass(void)
} }
static int 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; char *certpath = NULL, *comment = NULL;
int ret = -1; int r, ret = -1;
public = key_load_public(filename, &comment); if ((r = sshkey_load_public(filename, &public, &comment)) != 0) {
if (public == NULL) { printf("Bad key file %s: %s\n", filename, ssh_err(r));
printf("Bad key file %s\n", filename);
return -1; 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); fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
ret = 0; ret = 0;
} else } 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) if (key_only)
goto out; goto out;
@ -127,13 +128,13 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only)
free(comment); free(comment);
comment = NULL; comment = NULL;
xasprintf(&certpath, "%s-cert.pub", filename); 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; goto out;
if (!key_equal_public(cert, public)) if (!sshkey_equal_public(cert, public))
fatal("Certificate %s does not match private key %s", fatal("Certificate %s does not match private key %s",
certpath, filename); certpath, filename);
if (ssh_remove_identity(ac, cert)) { if (ssh_remove_identity(agent_fd, cert)) {
fprintf(stderr, "Identity removed: %s (%s)\n", certpath, fprintf(stderr, "Identity removed: %s (%s)\n", certpath,
comment); comment);
ret = 0; ret = 0;
@ -142,9 +143,9 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only)
out: out:
if (cert != NULL) if (cert != NULL)
key_free(cert); sshkey_free(cert);
if (public != NULL) if (public != NULL)
key_free(public); sshkey_free(public);
free(certpath); free(certpath);
free(comment); free(comment);
@ -153,14 +154,15 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only)
/* Send a request to remove all identities. */ /* Send a request to remove all identities. */
static int static int
delete_all(AuthenticationConnection *ac) delete_all(int agent_fd)
{ {
int ret = -1; int ret = -1;
if (ssh_remove_all_identities(ac, 1)) if (ssh_remove_all_identities(agent_fd, 1) == 0)
ret = 0; ret = 0;
/* ignore error-code for ssh2 */ /* ignore error-code for ssh2 */
ssh_remove_all_identities(ac, 2); /* XXX revisit */
ssh_remove_all_identities(agent_fd, 2);
if (ret == 0) if (ret == 0)
fprintf(stderr, "All identities removed.\n"); fprintf(stderr, "All identities removed.\n");
@ -171,13 +173,13 @@ delete_all(AuthenticationConnection *ac)
} }
static int 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 *comment = NULL;
char msg[1024], *certpath = NULL; char msg[1024], *certpath = NULL;
int r, fd, perms_ok, ret = -1; int r, fd, ret = -1;
Buffer keyblob; struct sshbuf *keyblob;
if (strcmp(filename, "-") == 0) { if (strcmp(filename, "-") == 0) {
fd = STDIN_FILENO; 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. * will occur multiple times, so check perms first and bail if wrong.
*/ */
if (fd != STDIN_FILENO) { if (fd != STDIN_FILENO) {
perms_ok = key_perm_ok(fd, filename); if (sshkey_perm_ok(fd, filename) != 0) {
if (!perms_ok) {
close(fd); close(fd);
return -1; return -1;
} }
} }
buffer_init(&keyblob); if ((keyblob = sshbuf_new()) == NULL)
if (!key_load_file(fd, filename, &keyblob)) { fatal("%s: sshbuf_new failed", __func__);
buffer_free(&keyblob); 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); close(fd);
return -1; return -1;
} }
close(fd); close(fd);
/* At first, try empty passphrase */ /* At first, try empty passphrase */
if ((r = sshkey_parse_private_fileblob(&keyblob, "", filename, if ((r = sshkey_parse_private_fileblob(keyblob, "", filename,
&private, &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) &private, &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) {
fatal("Cannot parse %s: %s", filename, ssh_err(r)); fprintf(stderr, "Error loading key \"%s\": %s\n",
filename, ssh_err(r));
goto fail_load;
}
/* try last */ /* try last */
if (private == NULL && pass != NULL) { 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 && &private, &comment)) != 0 &&
r != SSH_ERR_KEY_WRONG_PASSPHRASE) r != SSH_ERR_KEY_WRONG_PASSPHRASE) {
fatal("Cannot parse %s: %s", filename, ssh_err(r)); fprintf(stderr, "Error loading key \"%s\": %s\n",
filename, ssh_err(r));
goto fail_load;
}
} }
if (comment == NULL) if (comment == NULL)
comment = xstrdup(filename); comment = xstrdup(filename);
@ -226,28 +236,30 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
comment); comment);
for (;;) { for (;;) {
pass = read_passphrase(msg, RP_ALLOW_STDIN); 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(); clear_pass();
free(comment); free(comment);
buffer_free(&keyblob); sshbuf_free(keyblob);
return -1; 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(); clear_pass();
snprintf(msg, sizeof msg, snprintf(msg, sizeof msg,
"Bad passphrase, try again for %.200s: ", comment); "Bad passphrase, try again for %.200s: ", comment);
} }
} }
buffer_free(&keyblob); sshbuf_free(keyblob);
if (ssh_add_identity_constrained(ac, private, comment, lifetime, if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
confirm)) { lifetime, confirm)) == 0) {
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
ret = 0; ret = 0;
if (lifetime != 0) if (lifetime != 0)
@ -257,7 +269,8 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
fprintf(stderr, fprintf(stderr,
"The user must confirm each use of the key\n"); "The user must confirm each use of the key\n");
} else { } 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 */ /* 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 */ /* Now try to add the certificate flavour too */
xasprintf(&certpath, "%s-cert.pub", filename); 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; goto out;
}
if (!key_equal_public(cert, private)) { if (!sshkey_equal_public(cert, private)) {
error("Certificate %s does not match private key %s", error("Certificate %s does not match private key %s",
certpath, filename); certpath, filename);
key_free(cert); sshkey_free(cert);
goto out; goto out;
} }
/* Graft with private bits */ /* Graft with private bits */
if (key_to_certified(private, key_cert_is_legacy(cert)) != 0) { if ((r = sshkey_to_certified(private,
error("%s: key_to_certified failed", __func__); sshkey_cert_is_legacy(cert))) != 0) {
key_free(cert); error("%s: sshkey_to_certified: %s", __func__, ssh_err(r));
sshkey_free(cert);
goto out; goto out;
} }
key_cert_copy(cert, private); if ((r = sshkey_cert_copy(cert, private)) != 0) {
key_free(cert); 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, if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
lifetime, confirm)) { lifetime, confirm)) != 0) {
error("Certificate %s (%s) add failed", certpath, error("Certificate %s (%s) add failed: %s", certpath,
private->cert->key_id); private->cert->key_id, ssh_err(r));
goto out;
} }
fprintf(stderr, "Certificate added: %s (%s)\n", certpath, fprintf(stderr, "Certificate added: %s (%s)\n", certpath,
private->cert->key_id); private->cert->key_id);
@ -297,19 +320,18 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only)
if (confirm != 0) if (confirm != 0)
fprintf(stderr, "The user must confirm each use of the key\n"); fprintf(stderr, "The user must confirm each use of the key\n");
out: out:
if (certpath != NULL) free(certpath);
free(certpath);
free(comment); free(comment);
key_free(private); sshkey_free(private);
return ret; return ret;
} }
static int static int
update_card(AuthenticationConnection *ac, int add, const char *id) update_card(int agent_fd, int add, const char *id)
{ {
char *pin = NULL; char *pin = NULL;
int ret = -1; int r, ret = -1;
if (add) { if (add) {
if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", if ((pin = read_passphrase("Enter passphrase for PKCS#11: ",
@ -317,14 +339,14 @@ update_card(AuthenticationConnection *ac, int add, const char *id)
return -1; return -1;
} }
if (ssh_update_card(ac, add, id, pin == NULL ? "" : pin, if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin,
lifetime, confirm)) { lifetime, confirm)) == 0) {
fprintf(stderr, "Card %s: %s\n", fprintf(stderr, "Card %s: %s\n",
add ? "added" : "removed", id); add ? "added" : "removed", id);
ret = 0; ret = 0;
} else { } else {
fprintf(stderr, "Could not %s card: %s\n", fprintf(stderr, "Could not %s card \"%s\": %s\n",
add ? "add" : "remove", id); add ? "add" : "remove", id, ssh_err(r));
ret = -1; ret = -1;
} }
free(pin); free(pin);
@ -332,32 +354,42 @@ update_card(AuthenticationConnection *ac, int add, const char *id)
} }
static int static int
list_identities(AuthenticationConnection *ac, int do_fp) list_identities(int agent_fd, int do_fp)
{ {
Key *key; char *fp;
char *comment, *fp; int version, r, had_identities = 0;
int had_identities = 0; struct ssh_identitylist *idlist;
int version; size_t i;
for (version = 1; version <= 2; version++) { for (version = 1; version <= 2; version++) {
for (key = ssh_get_first_identity(ac, &comment, version); if ((r = ssh_fetch_identitylist(agent_fd, version,
key != NULL; &idlist)) != 0) {
key = ssh_get_next_identity(ac, &comment, version)) { 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; had_identities = 1;
if (do_fp) { if (do_fp) {
fp = key_fingerprint(key, fingerprint_hash, fp = sshkey_fingerprint(idlist->keys[i],
SSH_FP_DEFAULT); fingerprint_hash, SSH_FP_DEFAULT);
printf("%d %s %s (%s)\n", 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); free(fp);
} else { } else {
if (!key_write(key, stdout)) if ((r = sshkey_write(idlist->keys[i],
fprintf(stderr, "key_write failed"); stdout)) != 0) {
fprintf(stdout, " %s\n", comment); 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) { if (!had_identities) {
printf("The agent has no identities.\n"); printf("The agent has no identities.\n");
@ -367,10 +399,10 @@ list_identities(AuthenticationConnection *ac, int do_fp)
} }
static int static int
lock_agent(AuthenticationConnection *ac, int lock) lock_agent(int agent_fd, int lock)
{ {
char prompt[100], *p1, *p2; char prompt[100], *p1, *p2;
int passok = 1, ret = -1; int r, passok = 1, ret = -1;
strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); strlcpy(prompt, "Enter lock password: ", sizeof(prompt));
p1 = read_passphrase(prompt, RP_ALLOW_STDIN); p1 = read_passphrase(prompt, RP_ALLOW_STDIN);
@ -384,24 +416,28 @@ lock_agent(AuthenticationConnection *ac, int lock)
explicit_bzero(p2, strlen(p2)); explicit_bzero(p2, strlen(p2));
free(p2); free(p2);
} }
if (passok && ssh_lock_agent(ac, lock, p1)) { if (passok) {
fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) {
ret = 0; fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un");
} else ret = 0;
fprintf(stderr, "Failed to %slock agent.\n", lock ? "" : "un"); } else {
fprintf(stderr, "Failed to %slock agent: %s\n",
lock ? "" : "un", ssh_err(r));
}
}
explicit_bzero(p1, strlen(p1)); explicit_bzero(p1, strlen(p1));
free(p1); free(p1);
return (ret); return (ret);
} }
static int 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 (deleting) {
if (delete_file(ac, file, key_only) == -1) if (delete_file(agent_fd, file, key_only) == -1)
return -1; return -1;
} else { } else {
if (add_file(ac, file, key_only) == -1) if (add_file(agent_fd, file, key_only) == -1)
return -1; return -1;
} }
return 0; return 0;
@ -431,9 +467,9 @@ main(int argc, char **argv)
{ {
extern char *optarg; extern char *optarg;
extern int optind; extern int optind;
AuthenticationConnection *ac = NULL; int agent_fd;
char *pkcs11provider = NULL; 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; int xflag = 0, lflag = 0, Dflag = 0;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ /* 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); setvbuf(stdout, NULL, _IOLBF, 0);
/* At first, get a connection to the authentication agent. */ /* First, get a connection to the authentication agent. */
ac = ssh_get_authentication_connection(); switch (r = ssh_get_authentication_socket(&agent_fd)) {
if (ac == NULL) { case 0:
fprintf(stderr, break;
"Could not open a connection to your authentication agent.\n"); 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); exit(2);
} }
while ((ch = getopt(argc, argv, "klLcdDxXE:e:s:t:")) != -1) { while ((ch = getopt(argc, argv, "klLcdDxXE:e:s:t:")) != -1) {
switch (ch) { switch (ch) {
case 'E': case 'E':
@ -510,15 +552,15 @@ main(int argc, char **argv)
if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1) if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1)
fatal("Invalid combination of actions"); fatal("Invalid combination of actions");
else if (xflag) { else if (xflag) {
if (lock_agent(ac, xflag == 'x' ? 1 : 0) == -1) if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1)
ret = 1; ret = 1;
goto done; goto done;
} else if (lflag) { } else if (lflag) {
if (list_identities(ac, lflag == 'l' ? 1 : 0) == -1) if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1)
ret = 1; ret = 1;
goto done; goto done;
} else if (Dflag) { } else if (Dflag) {
if (delete_all(ac) == -1) if (delete_all(agent_fd) == -1)
ret = 1; ret = 1;
goto done; goto done;
} }
@ -526,7 +568,7 @@ main(int argc, char **argv)
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (pkcs11provider != NULL) { if (pkcs11provider != NULL) {
if (update_card(ac, !deleting, pkcs11provider) == -1) if (update_card(agent_fd, !deleting, pkcs11provider) == -1)
ret = 1; ret = 1;
goto done; goto done;
} }
@ -548,7 +590,7 @@ main(int argc, char **argv)
default_files[i]); default_files[i]);
if (stat(buf, &st) < 0) if (stat(buf, &st) < 0)
continue; continue;
if (do_file(ac, deleting, key_only, buf) == -1) if (do_file(agent_fd, deleting, key_only, buf) == -1)
ret = 1; ret = 1;
else else
count++; count++;
@ -557,13 +599,14 @@ main(int argc, char **argv)
ret = 1; ret = 1;
} else { } else {
for (i = 0; i < argc; i++) { 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; ret = 1;
} }
} }
clear_pass(); clear_pass();
done: done:
ssh_close_authentication_connection(ac); ssh_close_authentication_socket(agent_fd);
return ret; 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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -107,6 +107,7 @@
#include "uidswap.h" #include "uidswap.h"
#include "roaming.h" #include "roaming.h"
#include "version.h" #include "version.h"
#include "ssherr.h"
#ifdef ENABLE_PKCS11 #ifdef ENABLE_PKCS11
#include "ssh-pkcs11.h" #include "ssh-pkcs11.h"
@ -1502,10 +1503,16 @@ ssh_init_forwarding(void)
static void static void
check_agent_present(void) check_agent_present(void)
{ {
int r;
if (options.forward_agent) { if (options.forward_agent) {
/* Clear agent forwarding if we don't have an 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; 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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -22,6 +22,7 @@
#include <openssl/bn.h> #include <openssl/bn.h>
#include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -49,6 +50,7 @@
#include "hostfile.h" #include "hostfile.h"
#include "auth.h" #include "auth.h"
#include "digest.h" #include "digest.h"
#include "ssherr.h"
/* Session id for the current session. */ /* Session id for the current session. */
u_char session_id[16]; u_char session_id[16];
@ -64,33 +66,38 @@ extern char *__progname;
static int static int
try_agent_authentication(void) try_agent_authentication(void)
{ {
int type; int r, type, agent_fd, ret = 0;
char *comment;
AuthenticationConnection *auth;
u_char response[16]; u_char response[16];
u_int i; size_t i;
Key *key;
BIGNUM *challenge; BIGNUM *challenge;
struct ssh_identitylist *idlist = NULL;
/* Get connection to the agent. */ /* Get connection to the agent. */
auth = ssh_get_authentication_connection(); if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
if (!auth) if (r != SSH_ERR_AGENT_NOT_PRESENT)
debug("%s: ssh_get_authentication_socket: %s",
__func__, ssh_err(r));
return 0; return 0;
}
if ((challenge = BN_new()) == NULL) if ((challenge = BN_new()) == NULL)
fatal("try_agent_authentication: BN_new failed"); 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. */ /* Try this identity. */
debug("Trying RSA authentication via agent with '%.100s'", comment); debug("Trying RSA authentication via agent with '%.100s'",
free(comment); 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_start(SSH_CMSG_AUTH_RSA);
packet_put_bignum(key->rsa->n); packet_put_bignum(idlist->keys[i]->rsa->n);
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
@ -101,7 +108,6 @@ try_agent_authentication(void)
does not support RSA authentication. */ does not support RSA authentication. */
if (type == SSH_SMSG_FAILURE) { if (type == SSH_SMSG_FAILURE) {
debug("Server refused our key."); debug("Server refused our key.");
key_free(key);
continue; continue;
} }
/* Otherwise it should have sent a challenge. */ /* Otherwise it should have sent a challenge. */
@ -115,16 +121,17 @@ try_agent_authentication(void)
debug("Received RSA challenge from server."); debug("Received RSA challenge from server.");
/* Ask the agent to decrypt the challenge. */ /* 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 * The agent failed to authenticate this identifier
* although it advertised it supports this. Just * although it advertised it supports this. Just
* return a wrong value. * 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)); explicit_bzero(response, sizeof(response));
} }
key_free(key);
debug("Sending response to RSA challenge."); debug("Sending response to RSA challenge.");
/* Send the decrypted challenge back to the server. */ /* Send the decrypted challenge back to the server. */
@ -137,22 +144,25 @@ try_agent_authentication(void)
/* Wait for response from the server. */ /* Wait for response from the server. */
type = packet_read(); 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) { if (type == SSH_SMSG_SUCCESS) {
ssh_close_authentication_connection(auth);
BN_clear_free(challenge);
debug("RSA authentication accepted by server."); debug("RSA authentication accepted by server.");
return 1; ret = 1;
} break;
/* Otherwise it should return failure. */ } else if (type != SSH_SMSG_FAILURE)
if (type != SSH_SMSG_FAILURE) packet_disconnect("Protocol error waiting RSA auth "
packet_disconnect("Protocol error waiting RSA auth response: %d", "response: %d", type);
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); BN_clear_free(challenge);
debug("RSA authentication using agent refused."); return ret;
return 0;
} }
/* /*

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) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved.
@ -70,6 +70,7 @@
#include "pathnames.h" #include "pathnames.h"
#include "uidswap.h" #include "uidswap.h"
#include "hostfile.h" #include "hostfile.h"
#include "ssherr.h"
#ifdef GSSAPI #ifdef GSSAPI
#include "ssh-gss.h" #include "ssh-gss.h"
@ -131,10 +132,10 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
} while (0) } while (0)
while ((alg = strsep(&avail, ",")) && *alg != '\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); fatal("%s: unknown alg %s", __func__, alg);
if (lookup_key_in_hostkeys_by_type(hostkeys, if (lookup_key_in_hostkeys_by_type(hostkeys,
key_type_plain(ktype), NULL)) sshkey_type_plain(ktype), NULL))
ALG_APPEND(first, alg); ALG_APPEND(first, alg);
else else
ALG_APPEND(last, alg); ALG_APPEND(last, alg);
@ -242,15 +243,15 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
* Authenticate user * Authenticate user
*/ */
typedef struct Authctxt Authctxt; typedef struct cauthctxt Authctxt;
typedef struct Authmethod Authmethod; typedef struct cauthmethod Authmethod;
typedef struct identity Identity; typedef struct identity Identity;
typedef struct idlist Idlist; typedef struct idlist Idlist;
struct identity { struct identity {
TAILQ_ENTRY(identity) next; TAILQ_ENTRY(identity) next;
AuthenticationConnection *ac; /* set if agent supports key */ int agent_fd; /* >=0 if agent supports key */
Key *key; /* public/private key */ struct sshkey *key; /* public/private key */
char *filename; /* comment for agent-only keys */ char *filename; /* comment for agent-only keys */
int tried; int tried;
int isprivate; /* key points to the private key */ int isprivate; /* key points to the private key */
@ -258,17 +259,18 @@ struct identity {
}; };
TAILQ_HEAD(idlist, identity); TAILQ_HEAD(idlist, identity);
struct Authctxt { struct cauthctxt {
const char *server_user; const char *server_user;
const char *local_user; const char *local_user;
const char *host; const char *host;
const char *service; const char *service;
Authmethod *method; struct cauthmethod *method;
sig_atomic_t success; sig_atomic_t success;
char *authlist; char *authlist;
int attempt;
/* pubkey */ /* pubkey */
Idlist keys; struct idlist keys;
AuthenticationConnection *agent; int agent_fd;
/* hostbased */ /* hostbased */
Sensitive *sensitive; Sensitive *sensitive;
/* kbd-interactive */ /* kbd-interactive */
@ -276,7 +278,8 @@ struct Authctxt {
/* generic */ /* generic */
void *methoddata; void *methoddata;
}; };
struct Authmethod {
struct cauthmethod {
char *name; /* string to compare against server's list */ char *name; /* string to compare against server's list */
int (*userauth)(Authctxt *authctxt); int (*userauth)(Authctxt *authctxt);
void (*cleanup)(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); key->type, pktype);
goto done; 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); debug2("input_userauth_pk_ok: fp %s", fp);
free(fp); free(fp);
@ -956,27 +959,29 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
} }
static int static int
identity_sign(Identity *id, u_char **sigp, u_int *lenp, identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
u_char *data, u_int datalen) const u_char *data, size_t datalen, u_int compat)
{ {
Key *prv; Key *prv;
int ret; int ret;
/* the agent supports this key */ /* the agent supports this key */
if (id->ac) if (id->agent_fd)
return (ssh_agent_sign(id->ac, id->key, sigp, lenp, return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp,
data, datalen)); data, datalen, compat);
/* /*
* we have already loaded the private key or * we have already loaded the private key or
* the private key is stored in external hardware * the private key is stored in external hardware
*/ */
if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) 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 */ /* load the private key from the file */
if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL) if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL)
return (-1); return (-1); /* XXX return decent error code */
ret = key_sign(prv, sigp, lenp, data, datalen); ret = sshkey_sign(prv, sigp, lenp, data, datalen, compat);
key_free(prv); sshkey_free(prv);
return (ret); return (ret);
} }
@ -985,7 +990,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
{ {
Buffer b; Buffer b;
u_char *blob, *signature; u_char *blob, *signature;
u_int bloblen, slen; u_int bloblen;
size_t slen;
u_int skip = 0; u_int skip = 0;
int ret = -1; int ret = -1;
int have_sig = 1; int have_sig = 1;
@ -1026,8 +1032,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
/* generate signature */ /* generate signature */
ret = identity_sign(id, &signature, &slen, ret = identity_sign(id, &signature, &slen,
buffer_ptr(&b), buffer_len(&b)); buffer_ptr(&b), buffer_len(&b), datafellows);
if (ret == -1) { if (ret != 0) {
free(blob); free(blob);
buffer_free(&b); buffer_free(&b);
return 0; return 0;
@ -1102,7 +1108,7 @@ load_identity_file(char *filename, int userprovided)
{ {
Key *private; Key *private;
char prompt[300], *passphrase; char prompt[300], *passphrase;
int perm_ok = 0, quit, i; int r, perm_ok = 0, quit, i;
struct stat st; struct stat st;
if (stat(filename, &st) < 0) { if (stat(filename, &st) < 0) {
@ -1110,33 +1116,49 @@ load_identity_file(char *filename, int userprovided)
filename, strerror(errno)); filename, strerror(errno));
return NULL; return NULL;
} }
private = key_load_private_type(KEY_UNSPEC, filename, "", NULL, &perm_ok); snprintf(prompt, sizeof prompt,
if (!perm_ok) { "Enter passphrase for key '%.100s': ", filename);
if (private != NULL) for (i = 0; i <= options.number_of_password_prompts; i++) {
key_free(private); if (i == 0)
return NULL; passphrase = "";
} else {
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++) {
passphrase = read_passphrase(prompt, 0); passphrase = read_passphrase(prompt, 0);
if (strcmp(passphrase, "") != 0) { if (*passphrase == '\0') {
private = key_load_private_type(KEY_UNSPEC,
filename, passphrase, NULL, NULL);
quit = 0;
} else {
debug2("no passphrase given, try next key"); 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)); explicit_bzero(passphrase, strlen(passphrase));
free(passphrase); free(passphrase);
if (private != NULL || quit)
break;
debug2("bad passphrase given, try again...");
} }
if (private != NULL || quit)
break;
} }
return private; return private;
} }
@ -1150,12 +1172,12 @@ load_identity_file(char *filename, int userprovided)
static void static void
pubkey_prepare(Authctxt *authctxt) pubkey_prepare(Authctxt *authctxt)
{ {
Identity *id, *id2, *tmp; struct identity *id, *id2, *tmp;
Idlist agent, files, *preferred; struct idlist agent, files, *preferred;
Key *key; struct sshkey *key;
AuthenticationConnection *ac; int agent_fd, i, r, found;
char *comment; size_t j;
int i, found; struct ssh_identitylist *idlist;
TAILQ_INIT(&agent); /* keys from the agent */ TAILQ_INIT(&agent); /* keys from the agent */
TAILQ_INIT(&files); /* keys from the config file */ TAILQ_INIT(&files); /* keys from the config file */
@ -1185,7 +1207,7 @@ pubkey_prepare(Authctxt *authctxt)
if (id2->key == NULL || if (id2->key == NULL ||
(id2->key->flags & SSHKEY_FLAG_EXT) == 0) (id2->key->flags & SSHKEY_FLAG_EXT) == 0)
continue; continue;
if (key_equal(id->key, id2->key)) { if (sshkey_equal(id->key, id2->key)) {
TAILQ_REMOVE(&files, id, next); TAILQ_REMOVE(&files, id, next);
TAILQ_INSERT_TAIL(preferred, id, next); TAILQ_INSERT_TAIL(preferred, id, next);
found = 1; found = 1;
@ -1200,37 +1222,48 @@ pubkey_prepare(Authctxt *authctxt)
} }
} }
/* list of keys supported by the agent */ /* list of keys supported by the agent */
if ((ac = ssh_get_authentication_connection())) { if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
for (key = ssh_get_first_identity(ac, &comment, 2); if (r != SSH_ERR_AGENT_NOT_PRESENT)
key != NULL; debug("%s: ssh_get_authentication_socket: %s",
key = ssh_get_next_identity(ac, &comment, 2)) { __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; found = 0;
TAILQ_FOREACH(id, &files, next) { TAILQ_FOREACH(id, &files, next) {
/* agent keys from the config file are preferred */ /*
if (key_equal(key, id->key)) { * agent keys from the config file are
key_free(key); * preferred
free(comment); */
if (sshkey_equal(idlist->keys[j], id->key)) {
TAILQ_REMOVE(&files, id, next); TAILQ_REMOVE(&files, id, next);
TAILQ_INSERT_TAIL(preferred, id, next); TAILQ_INSERT_TAIL(preferred, id, next);
id->ac = ac; id->agent_fd = agent_fd;
found = 1; found = 1;
break; break;
} }
} }
if (!found && !options.identities_only) { if (!found && !options.identities_only) {
id = xcalloc(1, sizeof(*id)); id = xcalloc(1, sizeof(*id));
id->key = key; /* XXX "steals" key/comment from idlist */
id->filename = comment; id->key = idlist->keys[j];
id->ac = ac; id->filename = idlist->comments[j];
idlist->keys[j] = NULL;
idlist->comments[j] = NULL;
id->agent_fd = agent_fd;
TAILQ_INSERT_TAIL(&agent, id, next); TAILQ_INSERT_TAIL(&agent, id, next);
} }
} }
ssh_free_identitylist(idlist);
/* append remaining agent keys */ /* append remaining agent keys */
for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) {
TAILQ_REMOVE(&agent, id, next); TAILQ_REMOVE(&agent, id, next);
TAILQ_INSERT_TAIL(preferred, id, next); TAILQ_INSERT_TAIL(preferred, id, next);
} }
authctxt->agent = ac; authctxt->agent_fd = agent_fd;
} }
/* append remaining keys from the config file */ /* append remaining keys from the config file */
for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) {
@ -1248,13 +1281,13 @@ pubkey_cleanup(Authctxt *authctxt)
{ {
Identity *id; Identity *id;
if (authctxt->agent != NULL) if (authctxt->agent_fd != -1)
ssh_close_authentication_connection(authctxt->agent); ssh_close_authentication_socket(authctxt->agent_fd);
for (id = TAILQ_FIRST(&authctxt->keys); id; for (id = TAILQ_FIRST(&authctxt->keys); id;
id = TAILQ_FIRST(&authctxt->keys)) { id = TAILQ_FIRST(&authctxt->keys)) {
TAILQ_REMOVE(&authctxt->keys, id, next); TAILQ_REMOVE(&authctxt->keys, id, next);
if (id->key) if (id->key)
key_free(id->key); sshkey_free(id->key);
free(id->filename); free(id->filename);
free(id); 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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -123,6 +123,7 @@
#include "roaming.h" #include "roaming.h"
#include "ssh-sandbox.h" #include "ssh-sandbox.h"
#include "version.h" #include "version.h"
#include "ssherr.h"
#ifndef O_NOCTTY #ifndef O_NOCTTY
#define O_NOCTTY 0 #define O_NOCTTY 0
@ -191,7 +192,7 @@ char *server_version_string = NULL;
Kex *xxx_kex; Kex *xxx_kex;
/* Daemon's agent connection */ /* Daemon's agent connection */
AuthenticationConnection *auth_conn = NULL; int auth_sock = -1;
int have_agent = 0; int have_agent = 0;
/* /*
@ -655,7 +656,7 @@ privsep_preauth_child(void)
static int static int
privsep_preauth(Authctxt *authctxt) privsep_preauth(Authctxt *authctxt)
{ {
int status; int status, r;
pid_t pid; pid_t pid;
struct ssh_sandbox *box = NULL; struct ssh_sandbox *box = NULL;
@ -673,8 +674,14 @@ privsep_preauth(Authctxt *authctxt)
debug2("Network child is on pid %ld", (long)pid); debug2("Network child is on pid %ld", (long)pid);
pmonitor->m_pid = pid; pmonitor->m_pid = pid;
if (have_agent) if (have_agent) {
auth_conn = ssh_get_authentication_connection(); 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) if (box != NULL)
ssh_sandbox_parent_preauth(box, pid); ssh_sandbox_parent_preauth(box, pid);
monitor_child_preauth(authctxt, pmonitor); monitor_child_preauth(authctxt, pmonitor);
@ -1397,7 +1404,7 @@ main(int ac, char **av)
{ {
extern char *optarg; extern char *optarg;
extern int optind; 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; int sock_in = -1, sock_out = -1, newsock = -1;
const char *remote_ip; const char *remote_ip;
int remote_port; int remote_port;
@ -1706,7 +1713,7 @@ main(int ac, char **av)
if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME)) if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME))
setenv(SSH_AUTHSOCKET_ENV_NAME, setenv(SSH_AUTHSOCKET_ENV_NAME,
options.host_key_agent, 1); 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++) { for (i = 0; i < options.num_host_key_files; i++) {
@ -2103,8 +2110,12 @@ main(int ac, char **av)
if (use_privsep) { if (use_privsep) {
if (privsep_preauth(authctxt) == 1) if (privsep_preauth(authctxt) == 1)
goto authenticated; goto authenticated;
} else if (compat20 && have_agent) } else if (compat20 && have_agent) {
auth_conn = ssh_get_authentication_connection(); 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 */ /* perform the key exchange */
/* authenticate user and start session */ /* authenticate user and start session */
@ -2425,6 +2436,8 @@ void
sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen, sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen,
u_char *data, u_int dlen) u_char *data, u_int dlen)
{ {
int r;
if (privkey) { if (privkey) {
if (PRIVSEP(key_sign(privkey, signature, slen, data, dlen) < 0)) if (PRIVSEP(key_sign(privkey, signature, slen, data, dlen) < 0))
fatal("%s: key_sign failed", __func__); 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) if (mm_key_sign(pubkey, signature, slen, data, dlen) < 0)
fatal("%s: pubkey_sign failed", __func__); fatal("%s: pubkey_sign failed", __func__);
} else { } else {
if (ssh_agent_sign(auth_conn, pubkey, signature, slen, data, size_t xxx_slen;
dlen))
fatal("%s: ssh_agent_sign failed", __func__); 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;
} }
} }