summaryrefslogtreecommitdiff
path: root/usr.bin/ssh
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2000-08-19 21:34:45 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2000-08-19 21:34:45 +0000
commit3e0faeac47b31140f7d1afae467c8354d11f1b8c (patch)
treeb106e4cf366a597834d39c0a25da3d4bd212ca46 /usr.bin/ssh
parentc77945f9b968167988fecb8f47ab5f9652ffb647 (diff)
add SSH2/DSA support to the agent and some other DSA related cleanups.
(note that we cannot talk to ssh.com's ssh2 agents)
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r--usr.bin/ssh/authfd.c235
-rw-r--r--usr.bin/ssh/authfd.h53
-rw-r--r--usr.bin/ssh/fingerprint.c69
-rw-r--r--usr.bin/ssh/fingerprint.h34
-rw-r--r--usr.bin/ssh/key.c14
-rw-r--r--usr.bin/ssh/key.h4
-rw-r--r--usr.bin/ssh/lib/Makefile2
-rw-r--r--usr.bin/ssh/ssh-add.18
-rw-r--r--usr.bin/ssh/ssh-add.c81
-rw-r--r--usr.bin/ssh/ssh-agent.111
-rw-r--r--usr.bin/ssh/ssh-agent.c510
-rw-r--r--usr.bin/ssh/ssh-keygen.c19
-rw-r--r--usr.bin/ssh/sshconnect1.c40
-rw-r--r--usr.bin/ssh/sshconnect2.c78
14 files changed, 662 insertions, 496 deletions
diff --git a/usr.bin/ssh/authfd.c b/usr.bin/ssh/authfd.c
index e750ff61ec8..6372bae6cf0 100644
--- a/usr.bin/ssh/authfd.c
+++ b/usr.bin/ssh/authfd.c
@@ -11,10 +11,13 @@
*
* Functions for connecting the local authentication agent.
*
+ * SSH2 implementation,
+ * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ *
*/
#include "includes.h"
-RCSID("$OpenBSD: authfd.c,v 1.24 2000/08/15 19:20:46 markus Exp $");
+RCSID("$OpenBSD: authfd.c,v 1.25 2000/08/19 21:34:42 markus Exp $");
#include "ssh.h"
#include "rsa.h"
@@ -29,6 +32,7 @@ RCSID("$OpenBSD: authfd.c,v 1.24 2000/08/15 19:20:46 markus Exp $");
#include "key.h"
#include "authfd.h"
#include "kex.h"
+#include "dsa.h"
/* helper */
int decode_reply(int type);
@@ -67,8 +71,7 @@ ssh_get_authentication_socket()
}
int
-ssh_request_reply(AuthenticationConnection *auth,
- Buffer *request, Buffer *reply)
+ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)
{
int l, len;
char buf[1024];
@@ -158,7 +161,6 @@ ssh_get_authentication_connection()
auth = xmalloc(sizeof(*auth));
auth->fd = sock;
- buffer_init(&auth->packet);
buffer_init(&auth->identities);
auth->howmany = 0;
@@ -171,46 +173,57 @@ ssh_get_authentication_connection()
*/
void
-ssh_close_authentication_connection(AuthenticationConnection *ac)
+ssh_close_authentication_connection(AuthenticationConnection *auth)
{
- buffer_free(&ac->packet);
- buffer_free(&ac->identities);
- close(ac->fd);
- xfree(ac);
+ buffer_free(&auth->identities);
+ close(auth->fd);
+ xfree(auth);
}
/*
* Returns the first authentication identity held by the agent.
- * Returns true if an identity is available, 0 otherwise.
- * The caller must initialize the integers before the call, and free the
- * comment after a successful call (before calling ssh_get_next_identity).
*/
-int
-ssh_get_first_identity(AuthenticationConnection *auth,
- BIGNUM *e, BIGNUM *n, char **comment)
+Key *
+ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)
{
+ int type, code1 = 0, code2 = 0;
Buffer request;
- int type;
+
+ switch(version){
+ case 1:
+ code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
+ code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
+ break;
+ case 2:
+ code1 = SSH2_AGENTC_REQUEST_IDENTITIES;
+ code2 = SSH2_AGENT_IDENTITIES_ANSWER;
+ break;
+ default:
+ return NULL;
+ }
/*
* Send a message to the agent requesting for a list of the
* identities it can represent.
*/
buffer_init(&request);
- buffer_put_char(&request, SSH_AGENTC_REQUEST_RSA_IDENTITIES);
+ buffer_put_char(&request, code1);
buffer_clear(&auth->identities);
if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
buffer_free(&request);
- return 0;
+ return NULL;
}
buffer_free(&request);
/* Get message type, and verify that we got a proper answer. */
type = buffer_get_char(&auth->identities);
- if (type != SSH_AGENT_RSA_IDENTITIES_ANSWER)
+ if (type == SSH_AGENT_FAILURE) {
+ return NULL;
+ } else if (type != code2) {
fatal("Bad authentication reply message type: %d", type);
+ }
/* Get the number of entries in the response and check it for sanity. */
auth->howmany = buffer_get_int(&auth->identities);
@@ -219,43 +232,49 @@ ssh_get_first_identity(AuthenticationConnection *auth,
auth->howmany);
/* Return the first entry (if any). */
- return ssh_get_next_identity(auth, e, n, comment);
+ return ssh_get_next_identity(auth, comment, version);
}
-/*
- * Returns the next authentication identity for the agent. Other functions
- * can be called between this and ssh_get_first_identity or two calls of this
- * function. This returns 0 if there are no more identities. The caller
- * must free comment after a successful return.
- */
-
-int
-ssh_get_next_identity(AuthenticationConnection *auth,
- BIGNUM *e, BIGNUM *n, char **comment)
+Key *
+ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
{
unsigned int bits;
+ unsigned char *blob;
+ unsigned int blen;
+ Key *key = NULL;
/* Return failure if no more entries. */
if (auth->howmany <= 0)
- return 0;
+ return NULL;
/*
* Get the next entry from the packet. These will abort with a fatal
* error if the packet is too short or contains corrupt data.
*/
- bits = buffer_get_int(&auth->identities);
- buffer_get_bignum(&auth->identities, e);
- buffer_get_bignum(&auth->identities, n);
- *comment = buffer_get_string(&auth->identities, NULL);
-
- if (bits != BN_num_bits(n))
- log("Warning: identity keysize mismatch: actual %d, announced %u",
- BN_num_bits(n), bits);
-
+ switch(version){
+ case 1:
+ key = key_new(KEY_RSA);
+ bits = buffer_get_int(&auth->identities);
+ buffer_get_bignum(&auth->identities, key->rsa->e);
+ buffer_get_bignum(&auth->identities, key->rsa->n);
+ *comment = buffer_get_string(&auth->identities, NULL);
+ if (bits != BN_num_bits(key->rsa->n))
+ log("Warning: identity keysize mismatch: actual %d, announced %u",
+ BN_num_bits(key->rsa->n), bits);
+ break;
+ case 2:
+ blob = buffer_get_string(&auth->identities, &blen);
+ *comment = buffer_get_string(&auth->identities, NULL);
+ key = dsa_key_from_blob(blob, blen);
+ xfree(blob);
+ break;
+ default:
+ return NULL;
+ break;
+ }
/* Decrement the number of remaining entries. */
auth->howmany--;
-
- return 1;
+ return key;
}
/*
@@ -268,7 +287,7 @@ ssh_get_next_identity(AuthenticationConnection *auth,
int
ssh_decrypt_challenge(AuthenticationConnection *auth,
- BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
+ Key* key, BIGNUM *challenge,
unsigned char session_id[16],
unsigned int response_type,
unsigned char response[16])
@@ -278,15 +297,17 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
int i;
int type;
- if (response_type == 0)
- fatal("Compatibility with ssh protocol version "
- "1.0 no longer supported.");
-
+ if (key->type != KEY_RSA)
+ return 0;
+ if (response_type == 0) {
+ log("Compatibility with ssh protocol version 1.0 no longer supported.");
+ return 0;
+ }
buffer_init(&buffer);
buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE);
- buffer_put_int(&buffer, BN_num_bits(n));
- buffer_put_bignum(&buffer, e);
- buffer_put_bignum(&buffer, n);
+ buffer_put_int(&buffer, BN_num_bits(key->rsa->n));
+ buffer_put_bignum(&buffer, key->rsa->e);
+ buffer_put_bignum(&buffer, key->rsa->n);
buffer_put_bignum(&buffer, challenge);
buffer_append(&buffer, (char *) session_id, 16);
buffer_put_int(&buffer, response_type);
@@ -314,6 +335,45 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
return success;
}
+/* ask agent to sign data, returns -1 on error, 0 on success */
+int
+ssh_agent_sign(AuthenticationConnection *auth,
+ Key *key,
+ unsigned char **sigp, int *lenp,
+ unsigned char *data, int datalen)
+{
+ Buffer msg;
+ unsigned char *blob;
+ unsigned int blen;
+ int type;
+ int ret = -1;
+
+ if (dsa_make_key_blob(key, &blob, &blen) == 0)
+ return -1;
+
+ buffer_init(&msg);
+ buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST);
+ buffer_put_string(&msg, blob, blen);
+ buffer_put_string(&msg, data, datalen);
+ xfree(blob);
+
+ if (ssh_request_reply(auth, &msg, &msg) == 0) {
+ buffer_free(&msg);
+ return -1;
+ }
+ type = buffer_get_char(&msg);
+ if (type == SSH_AGENT_FAILURE) {
+ log("Agent admitted failure to sign using the key.");
+ } else if (type != SSH2_AGENT_SIGN_RESPONSE) {
+ fatal("Bad authentication response: %d", type);
+ } else {
+ ret = 0;
+ *sigp = buffer_get_string(&msg, lenp);
+ }
+ buffer_free(&msg);
+ return ret;
+}
+
/* Encode key for a message to the agent. */
void
@@ -354,29 +414,29 @@ ssh_encode_identity_dsa(Buffer *b, DSA *key, const char *comment)
int
ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
{
- Buffer buffer;
+ Buffer msg;
int type;
- buffer_init(&buffer);
+ buffer_init(&msg);
switch (key->type) {
case KEY_RSA:
- ssh_encode_identity_rsa(&buffer, key->rsa, comment);
+ ssh_encode_identity_rsa(&msg, key->rsa, comment);
break;
case KEY_DSA:
- ssh_encode_identity_dsa(&buffer, key->dsa, comment);
+ ssh_encode_identity_dsa(&msg, key->dsa, comment);
break;
default:
- buffer_free(&buffer);
+ buffer_free(&msg);
return 0;
break;
}
- if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
- buffer_free(&buffer);
+ if (ssh_request_reply(auth, &msg, &msg) == 0) {
+ buffer_free(&msg);
return 0;
}
- type = buffer_get_char(&buffer);
- buffer_free(&buffer);
+ type = buffer_get_char(&msg);
+ buffer_free(&msg);
return decode_reply(type);
}
@@ -386,23 +446,35 @@ ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
*/
int
-ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
+ssh_remove_identity(AuthenticationConnection *auth, Key *key)
{
- Buffer buffer;
+ Buffer msg;
int type;
-
- buffer_init(&buffer);
- buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
- buffer_put_int(&buffer, BN_num_bits(key->n));
- buffer_put_bignum(&buffer, key->e);
- buffer_put_bignum(&buffer, key->n);
-
- if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
- buffer_free(&buffer);
+ unsigned char *blob;
+ unsigned int blen;
+
+ buffer_init(&msg);
+
+ if (key->type == KEY_RSA) {
+ buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
+ buffer_put_int(&msg, BN_num_bits(key->rsa->n));
+ buffer_put_bignum(&msg, key->rsa->e);
+ buffer_put_bignum(&msg, key->rsa->n);
+ } else if (key->type == KEY_DSA) {
+ dsa_make_key_blob(key, &blob, &blen);
+ buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
+ buffer_put_string(&msg, blob, blen);
+ xfree(blob);
+ } else {
+ buffer_free(&msg);
return 0;
}
- type = buffer_get_char(&buffer);
- buffer_free(&buffer);
+ if (ssh_request_reply(auth, &msg, &msg) == 0) {
+ buffer_free(&msg);
+ return 0;
+ }
+ type = buffer_get_char(&msg);
+ buffer_free(&msg);
return decode_reply(type);
}
@@ -412,20 +484,23 @@ ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
*/
int
-ssh_remove_all_identities(AuthenticationConnection *auth)
+ssh_remove_all_identities(AuthenticationConnection *auth, int version)
{
- Buffer buffer;
+ Buffer msg;
int type;
+ int code = (version==1) ?
+ SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
+ SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
- buffer_init(&buffer);
- buffer_put_char(&buffer, SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES);
+ buffer_init(&msg);
+ buffer_put_char(&msg, code);
- if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
- buffer_free(&buffer);
+ if (ssh_request_reply(auth, &msg, &msg) == 0) {
+ buffer_free(&msg);
return 0;
}
- type = buffer_get_char(&buffer);
- buffer_free(&buffer);
+ type = buffer_get_char(&msg);
+ buffer_free(&msg);
return decode_reply(type);
}
diff --git a/usr.bin/ssh/authfd.h b/usr.bin/ssh/authfd.h
index 14b9bee94d6..5819b9139ea 100644
--- a/usr.bin/ssh/authfd.h
+++ b/usr.bin/ssh/authfd.h
@@ -13,7 +13,7 @@
*
*/
-/* RCSID("$OpenBSD: authfd.h,v 1.9 2000/07/16 08:27:21 markus Exp $"); */
+/* RCSID("$OpenBSD: authfd.h,v 1.10 2000/08/19 21:34:43 markus Exp $"); */
#ifndef AUTHFD_H
#define AUTHFD_H
@@ -35,18 +35,16 @@
#define SSH2_AGENT_IDENTITIES_ANSWER 12
#define SSH2_AGENTC_SIGN_REQUEST 13
#define SSH2_AGENT_SIGN_RESPONSE 14
-#define SSH2_AGENT_FAILURE SSH_AGENT_FAILURE
-#define SSH2_AGENT_SUCCESS SSH_AGENT_SUCCESS
#define SSH2_AGENTC_ADD_IDENTITY 17
#define SSH2_AGENTC_REMOVE_IDENTITY 18
#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19
typedef struct {
int fd;
- Buffer packet;
Buffer identities;
int howmany;
} AuthenticationConnection;
+
/* Returns the number of the authentication fd, or -1 if there is none. */
int ssh_get_authentication_socket();
@@ -69,44 +67,48 @@ AuthenticationConnection *ssh_get_authentication_connection();
* Closes the connection to the authentication agent and frees any associated
* memory.
*/
-void ssh_close_authentication_connection(AuthenticationConnection * ac);
+void ssh_close_authentication_connection(AuthenticationConnection *auth);
/*
- * Returns the first authentication identity held by the agent. Returns true
- * if an identity is available, 0 otherwise. The caller must initialize the
- * integers before the call, and free the comment after a successful call
- * (before calling ssh_get_next_identity).
+ * Returns the first authentication identity held by the agent or NULL if
+ * no identies are available. Caller must free comment and key.
+ * Note that you cannot mix calls with different versions.
*/
-int
-ssh_get_first_identity(AuthenticationConnection * connection,
- BIGNUM * e, BIGNUM * n, char **comment);
+Key *ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version);
/*
* Returns the next authentication identity for the agent. Other functions
* can be called between this and ssh_get_first_identity or two calls of this
- * function. This returns 0 if there are no more identities. The caller
- * must free comment after a successful return.
+ * function. This returns NULL if there are no more identities. The caller
+ * must free key and comment after a successful return.
*/
-int
-ssh_get_next_identity(AuthenticationConnection * connection,
- BIGNUM * e, BIGNUM * n, char **comment);
+Key *ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version);
-/* Requests the agent to decrypt the given challenge. Returns true if
- the agent claims it was able to decrypt it. */
+/*
+ * Requests the agent to decrypt the given challenge. Returns true if the
+ * agent claims it was able to decrypt it.
+ */
int
-ssh_decrypt_challenge(AuthenticationConnection * auth,
- BIGNUM * e, BIGNUM * n, BIGNUM * challenge,
+ssh_decrypt_challenge(AuthenticationConnection *auth,
+ Key *key, BIGNUM * challenge,
unsigned char session_id[16],
unsigned int response_type,
unsigned char response[16]);
+/* Requests the agent to sign data using key */
+int
+ssh_agent_sign(AuthenticationConnection *auth,
+ Key *key,
+ unsigned char **sigp, int *lenp,
+ unsigned char *data, int datalen);
+
/*
* Adds an identity to the authentication server. This call is not meant to
* be used by normal applications. This returns true if the identity was
* successfully added.
*/
int
-ssh_add_identity(AuthenticationConnection * connection, Key *key,
+ssh_add_identity(AuthenticationConnection *auth, Key *key,
const char *comment);
/*
@@ -114,16 +116,13 @@ ssh_add_identity(AuthenticationConnection * connection, Key *key,
* meant to be used by normal applications. This returns true if the
* identity was successfully added.
*/
-int ssh_remove_identity(AuthenticationConnection * connection, RSA * key);
+int ssh_remove_identity(AuthenticationConnection *auth, Key *key);
/*
* Removes all identities from the authentication agent. This call is not
* meant to be used by normal applications. This returns true if the
* operation was successful.
*/
-int ssh_remove_all_identities(AuthenticationConnection * connection);
-
-/* Closes the connection to the authentication agent. */
-void ssh_close_authentication(AuthenticationConnection * connection);
+int ssh_remove_all_identities(AuthenticationConnection *auth, int version);
#endif /* AUTHFD_H */
diff --git a/usr.bin/ssh/fingerprint.c b/usr.bin/ssh/fingerprint.c
deleted file mode 100644
index 801f6a6e297..00000000000
--- a/usr.bin/ssh/fingerprint.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 1999 Markus Friedl. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Markus Friedl.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-RCSID("$OpenBSD: fingerprint.c,v 1.7 2000/06/20 01:39:41 markus Exp $");
-
-#include "ssh.h"
-#include "xmalloc.h"
-#include <openssl/md5.h>
-
-#define FPRINT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
-
-/*
- * Generate key fingerprint in ascii format.
- * Based on ideas and code from Bjoern Groenvall <bg@sics.se>
- */
-char *
-fingerprint(BIGNUM *e, BIGNUM *n)
-{
- static char retval[80];
- MD5_CTX md;
- unsigned char d[16];
- unsigned char *buf;
- int nlen, elen;
-
- nlen = BN_num_bytes(n);
- elen = BN_num_bytes(e);
-
- buf = xmalloc(nlen + elen);
-
- BN_bn2bin(n, buf);
- BN_bn2bin(e, buf + nlen);
-
- MD5_Init(&md);
- MD5_Update(&md, buf, nlen + elen);
- MD5_Final(d, &md);
- snprintf(retval, sizeof(retval), FPRINT,
- d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
- d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
- memset(buf, 0, nlen + elen);
- xfree(buf);
- return retval;
-}
diff --git a/usr.bin/ssh/fingerprint.h b/usr.bin/ssh/fingerprint.h
deleted file mode 100644
index 3d7bcb32c2d..00000000000
--- a/usr.bin/ssh/fingerprint.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 1999 Markus Friedl. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Markus Friedl.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/* RCSID("$OpenBSD: fingerprint.h,v 1.4 2000/06/20 01:39:41 markus Exp $"); */
-
-#ifndef FINGERPRINT_H
-#define FINGERPRINT_H
-char *fingerprint(BIGNUM * e, BIGNUM * n);
-#endif
diff --git a/usr.bin/ssh/key.c b/usr.bin/ssh/key.c
index 764f1f227fb..f2ce75e7f1f 100644
--- a/usr.bin/ssh/key.c
+++ b/usr.bin/ssh/key.c
@@ -41,7 +41,7 @@
#include "dsa.h"
#include "uuencode.h"
-RCSID("$OpenBSD: key.c,v 1.9 2000/06/22 23:55:00 djm Exp $");
+RCSID("$OpenBSD: key.c,v 1.10 2000/08/19 21:34:43 markus Exp $");
#define SSH_DSS "ssh-dss"
@@ -335,3 +335,15 @@ key_type(Key *k)
}
return "unknown";
}
+unsigned int
+key_size(Key *k){
+ switch (k->type) {
+ case KEY_RSA:
+ return BN_num_bits(k->rsa->n);
+ break;
+ case KEY_DSA:
+ return BN_num_bits(k->dsa->p);
+ break;
+ }
+ return 0;
+}
diff --git a/usr.bin/ssh/key.h b/usr.bin/ssh/key.h
index ed3f770b8be..53b3bfb26fd 100644
--- a/usr.bin/ssh/key.h
+++ b/usr.bin/ssh/key.h
@@ -19,7 +19,7 @@ int key_equal(Key *a, Key *b);
char *key_fingerprint(Key *k);
char *key_type(Key *k);
int key_write(Key *key, FILE *f);
-unsigned int
-key_read(Key *key, char **cpp);
+unsigned int key_read(Key *key, char **cpp);
+unsigned int key_size(Key *k);
#endif
diff --git a/usr.bin/ssh/lib/Makefile b/usr.bin/ssh/lib/Makefile
index 7e2fe99ccd9..48a93d00a28 100644
--- a/usr.bin/ssh/lib/Makefile
+++ b/usr.bin/ssh/lib/Makefile
@@ -2,7 +2,7 @@
LIB= ssh
SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \
- cipher.c compat.c compress.c crc32.c deattack.c fingerprint.c \
+ cipher.c compat.c compress.c crc32.c deattack.c \
hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \
rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \
key.c dispatch.c dsa.c kex.c hmac.c uuencode.c util.c
diff --git a/usr.bin/ssh/ssh-add.1 b/usr.bin/ssh/ssh-add.1
index 10363956f8b..a0026d0cd8e 100644
--- a/usr.bin/ssh/ssh-add.1
+++ b/usr.bin/ssh/ssh-add.1
@@ -9,21 +9,21 @@
.\"
.\" Created: Sat Apr 22 23:55:14 1995 ylo
.\"
-.\" $Id: ssh-add.1,v 1.13 2000/05/03 18:04:38 markus Exp $
+.\" $Id: ssh-add.1,v 1.14 2000/08/19 21:34:43 markus Exp $
.\"
.Dd September 25, 1999
.Dt SSH-ADD 1
.Os
.Sh NAME
.Nm ssh-add
-.Nd adds RSA identities for the authentication agent
+.Nd adds RSA or DSA identities for the authentication agent
.Sh SYNOPSIS
.Nm ssh-add
.Op Fl lLdD
.Op Ar
.Sh DESCRIPTION
.Nm
-adds RSA identities to the authentication agent,
+adds RSA or DSA identities to the authentication agent,
.Xr ssh-agent 1 .
When run without arguments, it adds the file
.Pa $HOME/.ssh/identity .
@@ -63,6 +63,8 @@ used to encrypt the private part of this file.
This is the default file added by
.Nm
when no other files have been specified.
+.It Pa $HOME/.ssh/id_dsa
+Contains the DSA authentication identity of the user.
.Pp
.Sh ENVIRONMENT
.Bl -tag -width Ds
diff --git a/usr.bin/ssh/ssh-add.c b/usr.bin/ssh/ssh-add.c
index 5b4b598860b..ae5ca90d2fd 100644
--- a/usr.bin/ssh/ssh-add.c
+++ b/usr.bin/ssh/ssh-add.c
@@ -4,18 +4,21 @@
* All rights reserved
* Created: Thu Apr 6 00:52:24 1995 ylo
* Adds an identity to the authentication server, or removes an identity.
+ *
+ * SSH2 implementation,
+ * Copyright (c) 2000 Markus Friedl. All rights reserved.
*/
#include "includes.h"
-RCSID("$OpenBSD: ssh-add.c,v 1.18 2000/07/16 08:27:21 markus Exp $");
+RCSID("$OpenBSD: ssh-add.c,v 1.19 2000/08/19 21:34:43 markus Exp $");
+#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "rsa.h"
#include "ssh.h"
#include "xmalloc.h"
-#include "fingerprint.h"
#include "key.h"
#include "authfd.h"
#include "authfile.h"
@@ -31,7 +34,7 @@ delete_file(AuthenticationConnection *ac, const char *filename)
printf("Bad key file %s: %s\n", filename, strerror(errno));
return;
}
- if (ssh_remove_identity(ac, public->rsa))
+ if (ssh_remove_identity(ac, public))
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
else
fprintf(stderr, "Could not remove identity: %s\n", filename);
@@ -39,11 +42,18 @@ delete_file(AuthenticationConnection *ac, const char *filename)
xfree(comment);
}
+/* Send a request to remove all identities. */
void
delete_all(AuthenticationConnection *ac)
{
- /* Send a request to remove all identities. */
- if (ssh_remove_all_identities(ac))
+ int success = 1;
+
+ if (!ssh_remove_all_identities(ac, 1))
+ success = 0;
+ /* ignore error-code for ssh2 */
+ ssh_remove_all_identities(ac, 2);
+
+ if (success)
fprintf(stderr, "All identities removed.\n");
else
fprintf(stderr, "Failed to remove all identitities.\n");
@@ -90,6 +100,7 @@ ssh_askpass(char *askpass, char *msg)
void
add_file(AuthenticationConnection *ac, const char *filename)
{
+ struct stat st;
Key *public;
Key *private;
char *saved_comment, *comment, *askpass = NULL;
@@ -98,6 +109,10 @@ add_file(AuthenticationConnection *ac, const char *filename)
int interactive = isatty(STDIN_FILENO);
int type = KEY_RSA;
+ if (stat(filename, &st) < 0) {
+ perror(filename);
+ exit(1);
+ }
/*
* try to load the public key. right now this only works for RSA,
* since DSA keys are fully encrypted
@@ -148,54 +163,40 @@ add_file(AuthenticationConnection *ac, const char *filename)
strlcpy(msg, "Bad passphrase, try again", sizeof msg);
}
}
- xfree(saved_comment);
-
- if (ssh_add_identity(ac, private, comment))
- fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
+ xfree(comment);
+ if (ssh_add_identity(ac, private, saved_comment))
+ fprintf(stderr, "Identity added: %s (%s)\n", filename, saved_comment);
else
fprintf(stderr, "Could not add identity: %s\n", filename);
key_free(private);
- xfree(comment);
+ xfree(saved_comment);
}
void
list_identities(AuthenticationConnection *ac, int fp)
{
- BIGNUM *e, *n;
- int status;
+ Key *key;
char *comment;
- int had_identities;
+ int had_identities = 0;
+ int version;
- e = BN_new();
- n = BN_new();
- had_identities = 0;
- for (status = ssh_get_first_identity(ac, e, n, &comment);
- status;
- status = ssh_get_next_identity(ac, e, n, &comment)) {
- unsigned int bits = BN_num_bits(n);
- had_identities = 1;
- if (fp) {
- printf("%d %s %s\n", bits, fingerprint(e, n), comment);
- } else {
- char *ebuf, *nbuf;
- ebuf = BN_bn2dec(e);
- if (ebuf == NULL) {
- error("list_identities: BN_bn2dec(e) failed.");
+ 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)) {
+ had_identities = 1;
+ if (fp) {
+ printf("%d %s %s\n",
+ key_size(key), key_fingerprint(key), comment);
} else {
- nbuf = BN_bn2dec(n);
- if (nbuf == NULL) {
- error("list_identities: BN_bn2dec(n) failed.");
- } else {
- printf("%d %s %s %s\n", bits, ebuf, nbuf, comment);
- free(nbuf);
- }
- free(ebuf);
+ if (!key_write(key, stdout))
+ fprintf(stderr, "key_write failed");
+ fprintf(stdout, " %s\n", comment);
}
+ key_free(key);
+ xfree(comment);
}
- xfree(comment);
}
- BN_clear_free(e);
- BN_clear_free(n);
if (!had_identities)
printf("The agent has no identities.\n");
}
@@ -219,6 +220,8 @@ main(int argc, char **argv)
__progname);
exit(1);
}
+ SSLeay_add_all_algorithms();
+
/* At first, get a connection to the authentication agent. */
ac = ssh_get_authentication_connection();
if (ac == NULL) {
diff --git a/usr.bin/ssh/ssh-agent.1 b/usr.bin/ssh/ssh-agent.1
index d33ed29e8fb..f288bd127ee 100644
--- a/usr.bin/ssh/ssh-agent.1
+++ b/usr.bin/ssh/ssh-agent.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ssh-agent.1,v 1.13 2000/07/06 04:06:56 aaron Exp $
+.\" $OpenBSD: ssh-agent.1,v 1.14 2000/08/19 21:34:43 markus Exp $
.\"
.\" -*- nroff -*-
.\"
@@ -27,14 +27,15 @@
.Oc
.Sh DESCRIPTION
.Nm
-is a program to hold private keys used for RSA authentication.
+is a program to hold private keys used for public key authentication
+(RSA, DSA).
The idea is that
.Nm
is started in the beginning of an X-session or a login session, and
all other windows or programs are started as clients to the ssh-agent
program.
Through use of environment variables the agent can be located
-and automatically used for RSA authentication when logging in to other
+and automatically used for authentication when logging in to other
machines using
.Xr ssh 1 .
.Pp
@@ -128,7 +129,9 @@ This file is not used by
but is normally added to the agent using
.Xr ssh-add 1
at login time.
-.It Pa /tmp/ssh-XXXX/agent.<pid> ,
+.It Pa $HOME/.ssh/id_dsa
+Contains the DSA authentication identity of the user.
+.Pq Pa /tmp/ssh-XXXXXXXX/agent.<pid> ,
Unix-domain sockets used to contain the connection to the
authentication agent.
These sockets should only be readable by the owner.
diff --git a/usr.bin/ssh/ssh-agent.c b/usr.bin/ssh/ssh-agent.c
index 7e48819ed27..042ef1c522c 100644
--- a/usr.bin/ssh/ssh-agent.c
+++ b/usr.bin/ssh/ssh-agent.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.32 2000/07/16 08:27:21 markus Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.33 2000/08/19 21:34:43 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -6,10 +6,13 @@
* All rights reserved
* Created: Wed Mar 29 03:46:59 1995 ylo
* The authentication agent program.
+ *
+ * SSH2 implementation,
+ * Copyright (c) 2000 Markus Friedl. All rights reserved.
*/
#include "includes.h"
-RCSID("$OpenBSD: ssh-agent.c,v 1.32 2000/07/16 08:27:21 markus Exp $");
+RCSID("$OpenBSD: ssh-agent.c,v 1.33 2000/08/19 21:34:43 markus Exp $");
#include "ssh.h"
#include "rsa.h"
@@ -20,11 +23,14 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.32 2000/07/16 08:27:21 markus Exp $");
#include "getput.h"
#include "mpaux.h"
+#include <openssl/evp.h>
#include <openssl/md5.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include "key.h"
#include "authfd.h"
+#include "dsa.h"
+#include "kex.h"
typedef struct {
int fd;
@@ -39,12 +45,17 @@ unsigned int sockets_alloc = 0;
SocketEntry *sockets = NULL;
typedef struct {
- RSA *key;
+ Key *key;
char *comment;
} Identity;
-unsigned int num_identities = 0;
-Identity *identities = NULL;
+typedef struct {
+ int nentries;
+ Identity *identities;
+} Idtab;
+
+/* private key table, one per protocol version */
+Idtab idtable[3];
int max_fd = 0;
@@ -58,175 +69,243 @@ char socket_dir[1024];
extern char *__progname;
void
-process_request_identity(SocketEntry *e)
+idtab_init(void)
+{
+ int i;
+ for (i = 0; i <=2; i++){
+ idtable[i].identities = NULL;
+ idtable[i].nentries = 0;
+ }
+}
+
+/* return private key table for requested protocol version */
+Idtab *
+idtab_lookup(int version)
+{
+ if (version < 1 || version > 2)
+ fatal("internal error, bad protocol version %d", version);
+ return &idtable[version];
+}
+
+/* return matching private key for given public key */
+Key *
+lookup_private_key(Key *key, int *idx, int version)
+{
+ int i;
+ Idtab *tab = idtab_lookup(version);
+ for (i = 0; i < tab->nentries; i++) {
+ if (key_equal(key, tab->identities[i].key)) {
+ if (idx != NULL)
+ *idx = i;
+ return tab->identities[i].key;
+ }
+ }
+ return NULL;
+}
+
+/* send list of supported public keys to 'client' */
+void
+process_request_identities(SocketEntry *e, int version)
{
+ Idtab *tab = idtab_lookup(version);
Buffer msg;
int i;
buffer_init(&msg);
- buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
- buffer_put_int(&msg, num_identities);
- for (i = 0; i < num_identities; i++) {
- buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
- buffer_put_bignum(&msg, identities[i].key->e);
- buffer_put_bignum(&msg, identities[i].key->n);
- buffer_put_string(&msg, identities[i].comment,
- strlen(identities[i].comment));
+ buffer_put_char(&msg, (version == 1) ?
+ SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
+ buffer_put_int(&msg, tab->nentries);
+ for (i = 0; i < tab->nentries; i++) {
+ Identity *id = &tab->identities[i];
+ if (id->key->type == KEY_RSA) {
+ buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
+ buffer_put_bignum(&msg, id->key->rsa->e);
+ buffer_put_bignum(&msg, id->key->rsa->n);
+ } else {
+ unsigned char *blob;
+ unsigned int blen;
+ dsa_make_key_blob(id->key, &blob, &blen);
+ buffer_put_string(&msg, blob, blen);
+ xfree(blob);
+ }
+ buffer_put_cstring(&msg, id->comment);
}
buffer_put_int(&e->output, buffer_len(&msg));
buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
buffer_free(&msg);
}
+/* ssh1 only */
void
-process_authentication_challenge(SocketEntry *e)
+process_authentication_challenge1(SocketEntry *e)
{
- int i, pub_bits, len;
- BIGNUM *pub_e, *pub_n, *challenge;
+ Key *key, *private;
+ BIGNUM *challenge;
+ int i, len;
Buffer msg;
MD5_CTX md;
unsigned char buf[32], mdbuf[16], session_id[16];
unsigned int response_type;
buffer_init(&msg);
- pub_e = BN_new();
- pub_n = BN_new();
+ key = key_new(KEY_RSA);
challenge = BN_new();
- pub_bits = buffer_get_int(&e->input);
- buffer_get_bignum(&e->input, pub_e);
- buffer_get_bignum(&e->input, pub_n);
- buffer_get_bignum(&e->input, challenge);
- if (buffer_len(&e->input) == 0) {
- /* Compatibility code for old servers. */
- memset(session_id, 0, 16);
- response_type = 0;
- } else {
- /* New code. */
- buffer_get(&e->input, (char *) session_id, 16);
- response_type = buffer_get_int(&e->input);
- }
- for (i = 0; i < num_identities; i++)
- if (pub_bits == BN_num_bits(identities[i].key->n) &&
- BN_cmp(pub_e, identities[i].key->e) == 0 &&
- BN_cmp(pub_n, identities[i].key->n) == 0) {
- /* Decrypt the challenge using the private key. */
- rsa_private_decrypt(challenge, challenge, identities[i].key);
-
- /* Compute the desired response. */
- switch (response_type) {
- case 0:/* As of protocol 1.0 */
- /* This response type is no longer supported. */
- log("Compatibility with ssh protocol 1.0 no longer supported.");
- buffer_put_char(&msg, SSH_AGENT_FAILURE);
- goto send;
-
- case 1:/* As of protocol 1.1 */
- /* The response is MD5 of decrypted challenge plus session id. */
- len = BN_num_bytes(challenge);
-
- if (len <= 0 || len > 32) {
- fatal("process_authentication_challenge: "
- "bad challenge length %d", len);
- }
- memset(buf, 0, 32);
- BN_bn2bin(challenge, buf + 32 - len);
- MD5_Init(&md);
- MD5_Update(&md, buf, 32);
- MD5_Update(&md, session_id, 16);
- MD5_Final(mdbuf, &md);
- break;
-
- default:
- fatal("process_authentication_challenge: bad response_type %d",
- response_type);
- break;
- }
- /* Send the response. */
- buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
- for (i = 0; i < 16; i++)
- buffer_put_char(&msg, mdbuf[i]);
+ buffer_get_int(&e->input); /* ignored */
+ buffer_get_bignum(&e->input, key->rsa->e);
+ buffer_get_bignum(&e->input, key->rsa->n);
+ buffer_get_bignum(&e->input, challenge);
- goto send;
+ /* Only protocol 1.1 is supported */
+ if (buffer_len(&e->input) == 0)
+ goto failure;
+ buffer_get(&e->input, (char *) session_id, 16);
+ response_type = buffer_get_int(&e->input);
+ if (response_type != 1)
+ goto failure;
+
+ private = lookup_private_key(key, NULL, 1);
+ if (private != NULL) {
+ /* Decrypt the challenge using the private key. */
+ rsa_private_decrypt(challenge, challenge, private->rsa);
+
+ /* The response is MD5 of decrypted challenge plus session id. */
+ len = BN_num_bytes(challenge);
+ if (len <= 0 || len > 32) {
+ log("process_authentication_challenge: bad challenge length %d", len);
+ goto failure;
}
- /* Unknown identity. Send failure. */
+ memset(buf, 0, 32);
+ BN_bn2bin(challenge, buf + 32 - len);
+ MD5_Init(&md);
+ MD5_Update(&md, buf, 32);
+ MD5_Update(&md, session_id, 16);
+ MD5_Final(mdbuf, &md);
+
+ /* Send the response. */
+ buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
+ for (i = 0; i < 16; i++)
+ buffer_put_char(&msg, mdbuf[i]);
+ goto send;
+ }
+
+failure:
+ /* Unknown identity or protocol error. Send failure. */
buffer_put_char(&msg, SSH_AGENT_FAILURE);
send:
buffer_put_int(&e->output, buffer_len(&msg));
+ buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
+ key_free(key);
+ BN_clear_free(challenge);
+ buffer_free(&msg);
+}
+
+/* ssh2 only */
+void
+process_sign_request2(SocketEntry *e)
+{
+ extern int datafellows;
+ Key *key, *private;
+ unsigned char *blob, *data, *signature = NULL;
+ unsigned int blen, dlen, slen = 0;
+ Buffer msg;
+ int ok = -1;
+
+ datafellows = 0;
+
+ blob = buffer_get_string(&e->input, &blen);
+ data = buffer_get_string(&e->input, &dlen);
+
+ key = dsa_key_from_blob(blob, blen);
+ if (key != NULL) {
+ private = lookup_private_key(key, NULL, 2);
+ if (private != NULL)
+ ok = dsa_sign(private, &signature, &slen, data, dlen);
+ }
+ key_free(key);
+ buffer_init(&msg);
+ if (ok == 0) {
+ buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE);
+ buffer_put_string(&msg, signature, slen);
+ } else {
+ buffer_put_char(&msg, SSH_AGENT_FAILURE);
+ }
+ buffer_put_int(&e->output, buffer_len(&msg));
buffer_append(&e->output, buffer_ptr(&msg),
- buffer_len(&msg));
+ buffer_len(&msg));
buffer_free(&msg);
- BN_clear_free(pub_e);
- BN_clear_free(pub_n);
- BN_clear_free(challenge);
+ xfree(data);
+ xfree(blob);
+ if (signature != NULL)
+ xfree(signature);
}
+/* shared */
void
-process_remove_identity(SocketEntry *e)
+process_remove_identity(SocketEntry *e, int version)
{
+ Key *key = NULL, *private;
+ unsigned char *blob;
+ unsigned int blen;
unsigned int bits;
- unsigned int i;
- BIGNUM *dummy, *n;
-
- dummy = BN_new();
- n = BN_new();
-
- /* Get the key from the packet. */
- bits = buffer_get_int(&e->input);
- buffer_get_bignum(&e->input, dummy);
- buffer_get_bignum(&e->input, n);
-
- if (bits != BN_num_bits(n))
- log("Warning: identity keysize mismatch: actual %d, announced %d",
- BN_num_bits(n), bits);
-
- /* Check if we have the key. */
- for (i = 0; i < num_identities; i++)
- if (BN_cmp(identities[i].key->n, n) == 0) {
+ int success = 0;
+
+ switch(version){
+ case 1:
+ key = key_new(KEY_RSA);
+ bits = buffer_get_int(&e->input);
+ buffer_get_bignum(&e->input, key->rsa->e);
+ buffer_get_bignum(&e->input, key->rsa->n);
+
+ if (bits != key_size(key))
+ log("Warning: identity keysize mismatch: actual %d, announced %d",
+ key_size(key), bits);
+ break;
+ case 2:
+ blob = buffer_get_string(&e->input, &blen);
+ key = dsa_key_from_blob(blob, blen);
+ xfree(blob);
+ break;
+ }
+ if (key != NULL) {
+ int idx;
+ private = lookup_private_key(key, &idx, version);
+ if (private != NULL) {
/*
* We have this key. Free the old key. Since we
* don\'t want to leave empty slots in the middle of
* the array, we actually free the key there and copy
* data from the last entry.
*/
- RSA_free(identities[i].key);
- xfree(identities[i].comment);
- if (i < num_identities - 1)
- identities[i] = identities[num_identities - 1];
- num_identities--;
- BN_clear_free(dummy);
- BN_clear_free(n);
-
- /* Send success. */
- buffer_put_int(&e->output, 1);
- buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
- return;
+ Idtab *tab = idtab_lookup(version);
+ key_free(tab->identities[idx].key);
+ xfree(tab->identities[idx].comment);
+ if (idx != tab->nentries)
+ tab->identities[idx] = tab->identities[tab->nentries];
+ tab->nentries--;
+ success = 1;
}
- /* We did not have the key. */
- BN_clear(dummy);
- BN_clear(n);
-
- /* Send failure. */
+ key_free(key);
+ }
buffer_put_int(&e->output, 1);
- buffer_put_char(&e->output, SSH_AGENT_FAILURE);
+ buffer_put_char(&e->output,
+ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
}
-/*
- * Removes all identities from the agent.
- */
void
-process_remove_all_identities(SocketEntry *e)
+process_remove_all_identities(SocketEntry *e, int version)
{
unsigned int i;
+ Idtab *tab = idtab_lookup(version);
/* Loop over all identities and clear the keys. */
- for (i = 0; i < num_identities; i++) {
- RSA_free(identities[i].key);
- xfree(identities[i].comment);
+ for (i = 0; i < tab->nentries; i++) {
+ key_free(tab->identities[i].key);
+ xfree(tab->identities[i].comment);
}
/* Mark that there are no identities. */
- num_identities = 0;
+ tab->nentries = 0;
/* Send success. */
buffer_put_int(&e->output, 1);
@@ -234,79 +313,108 @@ process_remove_all_identities(SocketEntry *e)
return;
}
-/*
- * Adds an identity to the agent.
- */
void
-process_add_identity(SocketEntry *e)
+process_add_identity(SocketEntry *e, int version)
{
- RSA *k;
- int i;
+ Key *k = NULL;
+ RSA *rsa;
BIGNUM *aux;
BN_CTX *ctx;
+ char *type;
+ char *comment;
+ int success = 0;
+ Idtab *tab = idtab_lookup(version);
- if (num_identities == 0)
- identities = xmalloc(sizeof(Identity));
- else
- identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
-
- identities[num_identities].key = RSA_new();
- k = identities[num_identities].key;
- buffer_get_int(&e->input); /* bits */
- k->n = BN_new();
- buffer_get_bignum(&e->input, k->n);
- k->e = BN_new();
- buffer_get_bignum(&e->input, k->e);
- k->d = BN_new();
- buffer_get_bignum(&e->input, k->d);
- k->iqmp = BN_new();
- buffer_get_bignum(&e->input, k->iqmp);
- /* SSH and SSL have p and q swapped */
- k->q = BN_new();
- buffer_get_bignum(&e->input, k->q); /* p */
- k->p = BN_new();
- buffer_get_bignum(&e->input, k->p); /* q */
-
- /* Generate additional parameters */
- aux = BN_new();
- ctx = BN_CTX_new();
-
- BN_sub(aux, k->q, BN_value_one());
- k->dmq1 = BN_new();
- BN_mod(k->dmq1, k->d, aux, ctx);
-
- BN_sub(aux, k->p, BN_value_one());
- k->dmp1 = BN_new();
- BN_mod(k->dmp1, k->d, aux, ctx);
-
- BN_clear_free(aux);
- BN_CTX_free(ctx);
-
- identities[num_identities].comment = buffer_get_string(&e->input, NULL);
-
- /* Check if we already have the key. */
- for (i = 0; i < num_identities; i++)
- if (BN_cmp(identities[i].key->n, k->n) == 0) {
- /*
- * We already have this key. Clear and free the new
- * data and return success.
- */
- RSA_free(k);
- xfree(identities[num_identities].comment);
+ switch (version) {
+ case 1:
+ k = key_new(KEY_RSA);
+ rsa = k->rsa;
- /* Send success. */
- buffer_put_int(&e->output, 1);
- buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
- return;
+ /* allocate mem for private key */
+ /* XXX rsa->n and rsa->e are already allocated */
+ rsa->d = BN_new();
+ rsa->iqmp = BN_new();
+ rsa->q = BN_new();
+ rsa->p = BN_new();
+ rsa->dmq1 = BN_new();
+ rsa->dmp1 = BN_new();
+
+ buffer_get_int(&e->input); /* ignored */
+
+ buffer_get_bignum(&e->input, rsa->n);
+ buffer_get_bignum(&e->input, rsa->e);
+ buffer_get_bignum(&e->input, rsa->d);
+ buffer_get_bignum(&e->input, rsa->iqmp);
+
+ /* SSH and SSL have p and q swapped */
+ buffer_get_bignum(&e->input, rsa->q); /* p */
+ buffer_get_bignum(&e->input, rsa->p); /* q */
+
+ /* Generate additional parameters */
+ aux = BN_new();
+ ctx = BN_CTX_new();
+
+ BN_sub(aux, rsa->q, BN_value_one());
+ BN_mod(rsa->dmq1, rsa->d, aux, ctx);
+
+ BN_sub(aux, rsa->p, BN_value_one());
+ BN_mod(rsa->dmp1, rsa->d, aux, ctx);
+
+ BN_clear_free(aux);
+ BN_CTX_free(ctx);
+
+ break;
+ case 2:
+ type = buffer_get_string(&e->input, NULL);
+ if (strcmp(type, KEX_DSS)) {
+ buffer_clear(&e->input);
+ xfree(type);
+ goto send;
}
- /* Increment the number of identities. */
- num_identities++;
+ xfree(type);
+
+ k = key_new(KEY_DSA);
+
+ /* allocate mem for private key */
+ k->dsa->priv_key = BN_new();
+
+ buffer_get_bignum2(&e->input, k->dsa->p);
+ buffer_get_bignum2(&e->input, k->dsa->q);
+ buffer_get_bignum2(&e->input, k->dsa->g);
+ buffer_get_bignum2(&e->input, k->dsa->pub_key);
+ buffer_get_bignum2(&e->input, k->dsa->priv_key);
+
+ break;
+ }
- /* Send a success message. */
+ comment = buffer_get_string(&e->input, NULL);
+ if (k == NULL) {
+ xfree(comment);
+ goto send;
+ }
+ success = 1;
+ if (lookup_private_key(k, NULL, version) == NULL) {
+ if (tab->nentries == 0)
+ tab->identities = xmalloc(sizeof(Identity));
+ else
+ tab->identities = xrealloc(tab->identities,
+ (tab->nentries + 1) * sizeof(Identity));
+ tab->identities[tab->nentries].key = k;
+ tab->identities[tab->nentries].comment = comment;
+ /* Increment the number of identities. */
+ tab->nentries++;
+ } else {
+ key_free(k);
+ xfree(comment);
+ }
+send:
buffer_put_int(&e->output, 1);
- buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
+ buffer_put_char(&e->output,
+ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
}
+/* dispatch incoming messages */
+
void
process_message(SocketEntry *e)
{
@@ -329,20 +437,37 @@ process_message(SocketEntry *e)
type = buffer_get_char(&e->input);
switch (type) {
- case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
- process_request_identity(e);
- break;
+ /* ssh1 */
case SSH_AGENTC_RSA_CHALLENGE:
- process_authentication_challenge(e);
+ process_authentication_challenge1(e);
+ break;
+ case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
+ process_request_identities(e, 1);
break;
case SSH_AGENTC_ADD_RSA_IDENTITY:
- process_add_identity(e);
+ process_add_identity(e, 1);
break;
case SSH_AGENTC_REMOVE_RSA_IDENTITY:
- process_remove_identity(e);
+ process_remove_identity(e, 1);
break;
case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
- process_remove_all_identities(e);
+ process_remove_all_identities(e, 1);
+ break;
+ /* ssh2 */
+ case SSH2_AGENTC_SIGN_REQUEST:
+ process_sign_request2(e);
+ break;
+ case SSH2_AGENTC_REQUEST_IDENTITIES:
+ process_request_identities(e, 2);
+ break;
+ case SSH2_AGENTC_ADD_IDENTITY:
+ process_add_identity(e, 2);
+ break;
+ case SSH2_AGENTC_REMOVE_IDENTITY:
+ process_remove_identity(e, 2);
+ break;
+ case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
+ process_remove_all_identities(e, 2);
break;
default:
/* Unknown message. Respond with failure. */
@@ -643,6 +768,7 @@ main(int ac, char **av)
signal(SIGALRM, check_parent_exists);
alarm(10);
}
+ idtab_init();
signal(SIGINT, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, cleanup_exit);
diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c
index 3d5b8fb095c..8f69f8eedc0 100644
--- a/usr.bin/ssh/ssh-keygen.c
+++ b/usr.bin/ssh/ssh-keygen.c
@@ -7,7 +7,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: ssh-keygen.c,v 1.29 2000/07/15 04:01:37 djm Exp $");
+RCSID("$OpenBSD: ssh-keygen.c,v 1.30 2000/08/19 21:34:43 markus Exp $");
#include <openssl/evp.h>
#include <openssl/pem.h>
@@ -16,7 +16,6 @@ RCSID("$OpenBSD: ssh-keygen.c,v 1.29 2000/07/15 04:01:37 djm Exp $");
#include "ssh.h"
#include "xmalloc.h"
-#include "fingerprint.h"
#include "key.h"
#include "rsa.h"
#include "dsa.h"
@@ -224,8 +223,9 @@ do_print_public(struct passwd *pw)
void
do_fingerprint(struct passwd *pw)
{
+ /* XXX RSA1 only */
+
FILE *f;
- BIGNUM *e, *n;
Key *public;
char *comment = NULL, *cp, *ep, line[16*1024];
int i, skip = 0, num = 1, invalid = 1;
@@ -245,13 +245,9 @@ do_fingerprint(struct passwd *pw)
key_free(public);
exit(0);
}
- key_free(public);
- /* XXX */
f = fopen(identity_file, "r");
if (f != NULL) {
- n = BN_new();
- e = BN_new();
while (fgets(line, sizeof(line), f)) {
i = strlen(line) - 1;
if (line[i] != '\n') {
@@ -286,18 +282,17 @@ do_fingerprint(struct passwd *pw)
*cp++ = '\0';
}
ep = cp;
- if (auth_rsa_read_key(&cp, &ignore, e, n)) {
+ if (auth_rsa_read_key(&cp, &ignore, public->rsa->e, public->rsa->n)) {
invalid = 0;
comment = *cp ? cp : comment;
- printf("%d %s %s\n", BN_num_bits(n),
- fingerprint(e, n),
+ printf("%d %s %s\n", key_size(public),
+ key_fingerprint(public),
comment ? comment : "no comment");
}
}
- BN_free(e);
- BN_free(n);
fclose(f);
}
+ key_free(public);
if (invalid) {
printf("%s is not a valid key file.\n", identity_file);
exit(1);
diff --git a/usr.bin/ssh/sshconnect1.c b/usr.bin/ssh/sshconnect1.c
index aaebf17ffa1..7b60d6276ef 100644
--- a/usr.bin/ssh/sshconnect1.c
+++ b/usr.bin/ssh/sshconnect1.c
@@ -9,7 +9,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshconnect1.c,v 1.4 2000/07/16 08:27:22 markus Exp $");
+RCSID("$OpenBSD: sshconnect1.c,v 1.5 2000/08/19 21:34:44 markus Exp $");
#include <openssl/bn.h>
#include <openssl/dsa.h>
@@ -44,27 +44,27 @@ extern char *__progname;
int
try_agent_authentication()
{
- int status, type;
+ int type;
char *comment;
AuthenticationConnection *auth;
unsigned char response[16];
unsigned int i;
- BIGNUM *e, *n, *challenge;
+ int plen, clen;
+ Key *key;
+ BIGNUM *challenge;
/* Get connection to the agent. */
auth = ssh_get_authentication_connection();
if (!auth)
return 0;
- e = BN_new();
- n = BN_new();
challenge = BN_new();
+ key = key_new(KEY_RSA);
/* Loop through identities served by the agent. */
- for (status = ssh_get_first_identity(auth, e, n, &comment);
- status;
- status = ssh_get_next_identity(auth, e, n, &comment)) {
- int plen, clen;
+ for (key = ssh_get_first_identity(auth, &comment, 1);
+ key != NULL;
+ key = ssh_get_next_identity(auth, &comment, 1)) {
/* Try this identity. */
debug("Trying RSA authentication via agent with '%.100s'", comment);
@@ -72,7 +72,7 @@ try_agent_authentication()
/* Tell the server that we are willing to authenticate using this key. */
packet_start(SSH_CMSG_AUTH_RSA);
- packet_put_bignum(n);
+ packet_put_bignum(key->rsa->n);
packet_send();
packet_write_wait();
@@ -83,6 +83,7 @@ try_agent_authentication()
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. */
@@ -97,13 +98,16 @@ try_agent_authentication()
debug("Received RSA challenge from server.");
/* Ask the agent to decrypt the challenge. */
- if (!ssh_decrypt_challenge(auth, e, n, challenge,
- session_id, 1, response)) {
- /* The agent failed to authenticate this identifier although it
- advertised it supports this. Just return a wrong value. */
+ if (!ssh_decrypt_challenge(auth, key, challenge, session_id, 1, response)) {
+ /*
+ * The agent failed to authenticate this identifier
+ * although it advertised it supports this. Just
+ * return a wrong value.
+ */
log("Authentication agent failed to decrypt challenge.");
memset(response, 0, sizeof(response));
}
+ key_free(key);
debug("Sending response to RSA challenge.");
/* Send the decrypted challenge back to the server. */
@@ -118,10 +122,8 @@ try_agent_authentication()
/* The server returns success if it accepted the authentication. */
if (type == SSH_SMSG_SUCCESS) {
- debug("RSA authentication accepted by server.");
- BN_clear_free(e);
- BN_clear_free(n);
BN_clear_free(challenge);
+ debug("RSA authentication accepted by server.");
return 1;
}
/* Otherwise it should return failure. */
@@ -129,11 +131,7 @@ try_agent_authentication()
packet_disconnect("Protocol error waiting RSA auth response: %d",
type);
}
-
- BN_clear_free(e);
- BN_clear_free(n);
BN_clear_free(challenge);
-
debug("RSA authentication using agent refused.");
return 0;
}
diff --git a/usr.bin/ssh/sshconnect2.c b/usr.bin/ssh/sshconnect2.c
index 22ad39e7f38..1f49067adf0 100644
--- a/usr.bin/ssh/sshconnect2.c
+++ b/usr.bin/ssh/sshconnect2.c
@@ -28,7 +28,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshconnect2.c,v 1.16 2000/07/16 08:27:22 markus Exp $");
+RCSID("$OpenBSD: sshconnect2.c,v 1.17 2000/08/19 21:34:44 markus Exp $");
#include <openssl/bn.h>
#include <openssl/rsa.h>
@@ -54,6 +54,7 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.16 2000/07/16 08:27:22 markus Exp $");
#include "dsa.h"
#include "sshconnect.h"
#include "authfile.h"
+#include "authfd.h"
/* import */
extern char *client_version_string;
@@ -291,7 +292,7 @@ typedef int sign_fn(
unsigned char **sigp, int *lenp,
unsigned char *data, int datalen);
-void
+int
ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign,
const char *server_user, const char *host, const char *service)
{
@@ -299,6 +300,7 @@ ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign,
unsigned char *blob, *signature;
int bloblen, slen;
int skip = 0;
+ int ret = -1;
dsa_make_key_blob(k, &blob, &bloblen);
@@ -323,8 +325,12 @@ ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign,
buffer_put_string(&b, blob, bloblen);
/* generate signature */
- do_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
- key_free(k); /* XXX */
+ ret = do_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
+ if (ret == -1) {
+ xfree(blob);
+ buffer_free(&b);
+ return 0;
+ }
#ifdef DEBUG_DSS
buffer_dump(&b);
#endif
@@ -357,6 +363,8 @@ ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign,
/* send */
packet_send();
packet_write_wait();
+
+ return 1;
}
int
@@ -364,6 +372,7 @@ ssh2_try_pubkey(char *filename,
const char *server_user, const char *host, const char *service)
{
Key *k;
+ int ret = 0;
struct stat st;
if (stat(filename, &st) != 0) {
@@ -389,13 +398,53 @@ ssh2_try_pubkey(char *filename,
return 0;
}
}
- ssh2_sign_and_send_pubkey(k, dsa_sign, server_user, host, service);
- return 1;
+ ret = ssh2_sign_and_send_pubkey(k, dsa_sign, server_user, host, service);
+ key_free(k);
+ return ret;
+}
+
+int agent_sign(
+ Key *key,
+ unsigned char **sigp, int *lenp,
+ unsigned char *data, int datalen)
+{
+ int ret = -1;
+ AuthenticationConnection *ac = ssh_get_authentication_connection();
+ if (ac != NULL) {
+ ret = ssh_agent_sign(ac, key, sigp, lenp, data, datalen);
+ ssh_close_authentication_connection(ac);
+ }
+ return ret;
+}
+
+int
+ssh2_try_agent(AuthenticationConnection *ac,
+ const char *server_user, const char *host, const char *service)
+{
+ static int called = 0;
+ char *comment;
+ Key *k;
+ int ret;
+
+ if (called == 0) {
+ k = ssh_get_first_identity(ac, &comment, 2);
+ called ++;
+ } else {
+ k = ssh_get_next_identity(ac, &comment, 2);
+ }
+ if (k == NULL)
+ return 0;
+ debug("trying DSA agent key %s", comment);
+ xfree(comment);
+ ret = ssh2_sign_and_send_pubkey(k, agent_sign, server_user, host, service);
+ key_free(k);
+ return ret;
}
void
ssh_userauth2(const char *server_user, char *host)
{
+ AuthenticationConnection *ac = ssh_get_authentication_connection();
int type;
int plen;
int sent;
@@ -450,12 +499,17 @@ ssh_userauth2(const char *server_user, char *host)
debug("partial success");
if (options.dsa_authentication &&
strstr(auths, "publickey") != NULL) {
- while (i < options.num_identity_files2) {
- sent = ssh2_try_pubkey(
- options.identity_files2[i++],
+ if (ac != NULL)
+ sent = ssh2_try_agent(ac,
server_user, host, service);
- if (sent)
- break;
+ if (!sent) {
+ while (i < options.num_identity_files2) {
+ sent = ssh2_try_pubkey(
+ options.identity_files2[i++],
+ server_user, host, service);
+ if (sent)
+ break;
+ }
}
}
if (!sent) {
@@ -469,6 +523,8 @@ ssh_userauth2(const char *server_user, char *host)
fatal("Permission denied (%s).", auths);
xfree(auths);
}
+ if (ac != NULL)
+ ssh_close_authentication_connection(ac);
packet_done();
debug("ssh-userauth2 successfull");
}