changeset 45:9ee8996a375f

Pubkey auth is mostly there for the client. Something strange with remote hostkey verification though.
author Matt Johnston <matt@ucc.asn.au>
date Tue, 03 Aug 2004 17:26:56 +0000
parents 45edf30ea0a6
children 3bea78e1b175
files auth.h cli-auth.c cli-authpubkey.c cli-service.c cli-session.c dbutil.c debug.h session.h svr-session.c
diffstat 9 files changed, 222 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/auth.h	Tue Aug 03 15:51:55 2004 +0000
+++ b/auth.h	Tue Aug 03 17:26:56 2004 +0000
@@ -30,24 +30,24 @@
 void svr_authinitialise();
 void cli_authinitialise();
 
-void svr_auth_password();
-void svr_auth_pubkey();
-
-int cli_auth_password();
-int cli_auth_pubkey();
-
 /* Server functions */
 void recv_msg_userauth_request();
 void send_msg_userauth_failure(int partial, int incrfail);
 void send_msg_userauth_success();
+void svr_auth_password();
+void svr_auth_pubkey();
 
 /* Client functions */
 void recv_msg_userauth_failure();
 void recv_msg_userauth_success();
+void recv_msg_userauth_pk_ok();
 void cli_get_user();
 void cli_auth_getmethods();
 void cli_auth_try();
 void recv_msg_userauth_banner();
+void cli_pubkeyfail();
+int cli_auth_password();
+int cli_auth_pubkey();
 
 
 #define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
@@ -63,6 +63,9 @@
 #define AUTH_METHOD_PASSWORD "password"
 #define AUTH_METHOD_PASSWORD_LEN 8
 
+/* For a 4096 bit DSS key, empirically determined to be 1590 bytes */
+#define MAX_PUBKEY_SIZE 1600
+
 /* This structure is shared between server and client - it contains
  * relatively little extraneous bits when used for the client rather than the
  * server */
@@ -83,4 +86,16 @@
 
 };
 
+struct PubkeyList;
+/* A singly linked list of pubkeys */
+struct PubkeyList {
+
+	sign_key *key;
+	int type; /* The type of key */
+	struct PubkeyList *next;
+	/* filename? or the buffer? for encrypted keys, so we can later get
+	 * the private key portion */
+
+};
+
 #endif /* _AUTH_H_ */
--- a/cli-auth.c	Tue Aug 03 15:51:55 2004 +0000
+++ b/cli-auth.c	Tue Aug 03 17:26:56 2004 +0000
@@ -7,7 +7,6 @@
 #include "packet.h"
 #include "runopts.h"
 
-#undef DROPBEAR_PUBKEY_AUTH
 
 void cli_authinitialise() {
 
@@ -30,7 +29,6 @@
 	buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
 
 	encrypt_packet();
-	cli_ses.state = USERAUTH_METHODS_SENT;
 	TRACE(("leave cli_auth_getmethods"));
 
 }
@@ -88,6 +86,20 @@
 	TRACE(("<- MSG_USERAUTH_FAILURE"));
 	TRACE(("enter recv_msg_userauth_failure"));
 
+	if (cli_ses.state != USERAUTH_REQ_SENT) {
+		/* Perhaps we should be more fatal? */
+		TRACE(("But we didn't send a userauth request!!!!!!"));
+		return;
+	}
+
+#ifdef DROPBEAR_PUBKEY_AUTH
+	/* If it was a pubkey auth request, we should cross that key 
+	 * off the list. */
+	if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
+		cli_pubkeyfail();
+	}
+#endif
+
 	methods = buf_getstring(ses.payload, &methlen);
 
 	partial = buf_getbyte(ses.payload);
@@ -154,12 +166,14 @@
 #ifdef DROPBEAR_PUBKEY_AUTH
 	if (ses.authstate.authtypes & AUTH_TYPE_PUBKEY) {
 		finished = cli_auth_pubkey();
+		cli_ses.lastauthtype = AUTH_TYPE_PUBKEY;
 	}
 #endif
 
 #ifdef DROPBEAR_PASSWORD_AUTH
 	if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
 		finished = cli_auth_password();
+		cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
 	}
 #endif
 
@@ -167,6 +181,5 @@
 		dropbear_exit("No auth methods could be used.");
 	}
 
-	cli_ses.state = USERAUTH_REQ_SENT;
 	TRACE(("leave cli_auth_try"));
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cli-authpubkey.c	Tue Aug 03 17:26:56 2004 +0000
@@ -0,0 +1,146 @@
+#include "includes.h"
+#include "buffer.h"
+#include "dbutil.h"
+#include "session.h"
+#include "ssh.h"
+#include "runopts.h"
+#include "auth.h"
+
+static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
+
+/* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
+ * We use it to remove the key we tried from the list */
+void cli_pubkeyfail() {
+
+	struct PubkeyList *keyitem;
+
+	TRACE(("enter cli_pubkeyfail"));
+	/* Find the key we failed with, and remove it */
+	for (keyitem = cli_ses.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
+		if (keyitem->next == cli_ses.lastpubkey) {
+			keyitem->next = cli_ses.lastpubkey->next;
+		}
+	}
+
+	sign_key_free(cli_ses.lastpubkey->key); /* It won't be used again */
+	m_free(cli_ses.lastpubkey);
+	TRACE(("leave cli_pubkeyfail"));
+}
+
+void recv_msg_userauth_pk_ok() {
+
+	struct PubkeyList *keyitem;
+	buffer* keybuf;
+	char* algotype = NULL;
+	unsigned int algolen;
+	int keytype;
+	unsigned int remotelen;
+
+	TRACE(("enter recv_msg_userauth_pk_ok"));
+
+	algotype = buf_getstring(ses.payload, &algolen);
+	keytype = signkey_type_from_name(algotype, algolen);
+	m_free(algotype);
+
+	keybuf = buf_new(MAX_PUBKEY_SIZE);
+
+	remotelen = buf_getint(ses.payload);
+
+	/* Iterate through our keys, find which one it was that matched, and
+	 * send a real request with that key */
+	for (keyitem = cli_ses.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
+
+		if (keyitem->type != keytype) {
+			/* Types differed */
+			continue;
+		}
+
+		/* Now we compare the contents of the key */
+		keybuf->pos = keybuf->len = 0;
+		buf_put_pub_key(keybuf, keyitem->key, keytype);
+
+		if (keybuf->len != remotelen) {
+			/* Lengths differed */
+			continue;
+		}
+
+		if (memcmp(keybuf->data, 
+					buf_getptr(ses.payload, remotelen), remotelen) != 0) {
+			/* Data didn't match this key */
+			continue;
+		}
+
+		/* Success */
+		break;
+	}
+
+	if (keyitem != NULL) {
+		TRACE(("matching key"));
+		/* XXX TODO: if it's an encrypted key, here we ask for their
+		 * password */
+		send_msg_userauth_pubkey(keyitem->key, keytype, 1);
+	} else {
+		TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"));
+	}
+
+	TRACE(("leave recv_msg_userauth_pk_ok"));
+}
+
+/* TODO: make it take an agent reference to use as well */
+static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
+
+	const char *algoname = NULL;
+	int algolen;
+	buffer* sigbuf = NULL;
+
+	TRACE(("enter send_msg_userauth_pubkey"));
+	CHECKCLEARTOWRITE();
+
+	buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
+
+	buf_putstring(ses.writepayload, cli_opts.username,
+			strlen(cli_opts.username));
+
+	buf_putstring(ses.writepayload, SSH_SERVICE_CONNECTION, 
+			SSH_SERVICE_CONNECTION_LEN);
+
+	buf_putstring(ses.writepayload, AUTH_METHOD_PUBKEY, 
+			AUTH_METHOD_PUBKEY_LEN);
+
+	buf_putbyte(ses.writepayload, realsign);
+
+	algoname = signkey_name_from_type(type, &algolen);
+
+	buf_putstring(ses.writepayload, algoname, algolen);
+	buf_put_pub_key(ses.writepayload, key, type);
+
+	if (realsign) {
+		TRACE(("realsign"));
+		/* We put the signature as well - this contains string(session id), then
+		 * the contents of the write payload to this point */
+		sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
+		buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
+		buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
+		buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
+		buf_free(sigbuf); /* Nothing confidential in the buffer */
+	}
+
+	encrypt_packet();
+	TRACE(("leave send_msg_userauth_pubkey"));
+}
+
+int cli_auth_pubkey() {
+
+	TRACE(("enter cli_auth_pubkey"));
+
+	if (cli_ses.pubkeys != NULL) {
+		/* Send a trial request */
+		send_msg_userauth_pubkey(cli_ses.pubkeys->key,
+				cli_ses.pubkeys->type, 0);
+		TRACE(("leave cli_auth_pubkey-success"));
+		return 1;
+	} else {
+		TRACE(("leave cli_auth_pubkey-failure"));
+		return 0;
+	}
+}
--- a/cli-service.c	Tue Aug 03 15:51:55 2004 +0000
+++ b/cli-service.c	Tue Aug 03 17:26:56 2004 +0000
@@ -31,7 +31,7 @@
 	servicename = buf_getstring(ses.payload, &len);
 
 	/* ssh-userauth */
-	if (cli_ses.state = SERVICE_AUTH_REQ_SENT
+	if (cli_ses.state == SERVICE_AUTH_REQ_SENT
 			&& len == SSH_SERVICE_USERAUTH_LEN
 			&& strncmp(SSH_SERVICE_USERAUTH, servicename, len) == 0) {
 
@@ -42,7 +42,7 @@
 	}
 
 	/* ssh-connection */
-	if (cli_ses.state = SERVICE_CONN_REQ_SENT
+	if (cli_ses.state == SERVICE_CONN_REQ_SENT
 			&& len == SSH_SERVICE_CONNECTION_LEN 
 			&& strncmp(SSH_SERVICE_CONNECTION, servicename, len) == 0) {
 
--- a/cli-session.c	Tue Aug 03 15:51:55 2004 +0000
+++ b/cli-session.c	Tue Aug 03 17:26:56 2004 +0000
@@ -19,14 +19,18 @@
 
 struct clientsession cli_ses; /* GLOBAL */
 
+/* Sorted in decreasing frequency will be more efficient - data and window
+ * should be first */
 static const packettype cli_packettypes[] = {
 	/* TYPE, AUTHREQUIRED, FUNCTION */
-	{SSH_MSG_KEXINIT, recv_msg_kexinit},
-	{SSH_MSG_KEXDH_REPLY, recv_msg_kexdh_reply}, // client
-	{SSH_MSG_NEWKEYS, recv_msg_newkeys},
-	{SSH_MSG_SERVICE_ACCEPT, recv_msg_service_accept}, // client
 	{SSH_MSG_CHANNEL_DATA, recv_msg_channel_data},
 	{SSH_MSG_CHANNEL_WINDOW_ADJUST, recv_msg_channel_window_adjust},
+	{SSH_MSG_USERAUTH_FAILURE, recv_msg_userauth_failure}, /* client */
+	{SSH_MSG_USERAUTH_SUCCESS, recv_msg_userauth_success}, /* client */
+	{SSH_MSG_KEXINIT, recv_msg_kexinit},
+	{SSH_MSG_KEXDH_REPLY, recv_msg_kexdh_reply}, /* client */
+	{SSH_MSG_NEWKEYS, recv_msg_newkeys},
+	{SSH_MSG_SERVICE_ACCEPT, recv_msg_service_accept}, /* client */
 	{SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_remotetcp},
 	{SSH_MSG_CHANNEL_REQUEST, recv_msg_channel_request},
 	{SSH_MSG_CHANNEL_OPEN, recv_msg_channel_open},
@@ -34,9 +38,10 @@
 	{SSH_MSG_CHANNEL_CLOSE, recv_msg_channel_close},
 	{SSH_MSG_CHANNEL_OPEN_CONFIRMATION, recv_msg_channel_open_confirmation},
 	{SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
-	{SSH_MSG_USERAUTH_FAILURE, recv_msg_userauth_failure}, // client
-	{SSH_MSG_USERAUTH_SUCCESS, recv_msg_userauth_success}, // client
-	{SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, // client
+	{SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */
+#ifdef DROPBEAR_PUBKEY_AUTH
+	{SSH_MSG_USERAUTH_PK_OK, recv_msg_userauth_pk_ok}, /* client */
+#endif
 	{0, 0} /* End */
 };
 
@@ -145,28 +150,35 @@
 		/* userauth code */
 		case SERVICE_AUTH_ACCEPT_RCVD:
 			cli_auth_getmethods();
-			cli_ses.state = USERAUTH_METHODS_SENT;
+			cli_ses.state = USERAUTH_REQ_SENT;
 			TRACE(("leave cli_sessionloop: sent userauth methods req"));
 			return;
 			
 		case USERAUTH_FAIL_RCVD:
 			cli_auth_try();
+			cli_ses.state = USERAUTH_REQ_SENT;
 			TRACE(("leave cli_sessionloop: cli_auth_try"));
 			return;
 
-			/*
 		case USERAUTH_SUCCESS_RCVD:
 			send_msg_service_request(SSH_SERVICE_CONNECTION);
 			cli_ses.state = SERVICE_CONN_REQ_SENT;
 			TRACE(("leave cli_sessionloop: sent ssh-connection service req"));
 			return;
-			*/
 
+		case SERVICE_CONN_ACCEPT_RCVD:
+			cli_send_chansess_request();
+			TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
+			cli_ses.state = SESSION_RUNNING;
+			return;
+
+			/*
 		case USERAUTH_SUCCESS_RCVD:
 			cli_send_chansess_request();
 			TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
 			cli_ses.state = SESSION_RUNNING;
 			return;
+			*/
 
 		case SESSION_RUNNING:
 			if (ses.chancount < 1) {
--- a/dbutil.c	Tue Aug 03 15:51:55 2004 +0000
+++ b/dbutil.c	Tue Aug 03 17:26:56 2004 +0000
@@ -103,7 +103,6 @@
 #ifdef DEBUG_TRACE
 void dropbear_trace(const char* format, ...) {
 
-#if 0
 	va_list param;
 
 	va_start(param, format);
@@ -111,7 +110,6 @@
 	vfprintf(stderr, format, param);
 	fprintf(stderr, "\n");
 	va_end(param);
-#endif
 }
 #endif /* DEBUG_TRACE */
 
--- a/debug.h	Tue Aug 03 15:51:55 2004 +0000
+++ b/debug.h	Tue Aug 03 17:26:56 2004 +0000
@@ -36,7 +36,7 @@
 /* Define this to print trace statements - very verbose */
 /* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
  * since the printing does not sanitise strings etc */
-#define DEBUG_TRACE
+//#define DEBUG_TRACE
 
 /* All functions writing to the cleartext payload buffer call
  * CHECKCLEARTOWRITE() before writing. This is only really useful if you're
--- a/session.h	Tue Aug 03 15:51:55 2004 +0000
+++ b/session.h	Tue Aug 03 17:26:56 2004 +0000
@@ -194,7 +194,6 @@
 	SERVICE_AUTH_ACCEPT_RCVD,
 	SERVICE_CONN_REQ_SENT,
 	SERVICE_CONN_ACCEPT_RCVD,
-	USERAUTH_METHODS_SENT,
 	USERAUTH_REQ_SENT,
 	USERAUTH_FAIL_RCVD,
 	USERAUTH_SUCCESS_RCVD,
@@ -215,6 +214,15 @@
 
 	int winchange; /* Set to 1 when a windowchange signal happens */
 
+	struct PubkeyList *pubkeys; /* Keys to use for public-key auth */
+	int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
+						 for the last type of auth we tried */
+	struct PubkeyList *lastpubkey;
+#if 0
+	TODO
+	struct AgentkeyList *agentkeys; /* Keys to use for public-key auth */
+#endif
+
 };
 
 /* Global structs storing the state */
--- a/svr-session.c	Tue Aug 03 15:51:55 2004 +0000
+++ b/svr-session.c	Tue Aug 03 17:26:56 2004 +0000
@@ -46,14 +46,13 @@
 struct serversession svr_ses; /* GLOBAL */
 
 static const packettype svr_packettypes[] = {
-	/* TYPE, AUTHREQUIRED, FUNCTION */
-	{SSH_MSG_SERVICE_REQUEST, recv_msg_service_request}, // server
-	{SSH_MSG_USERAUTH_REQUEST, recv_msg_userauth_request}, //server
-	{SSH_MSG_KEXINIT, recv_msg_kexinit},
-	{SSH_MSG_KEXDH_INIT, recv_msg_kexdh_init}, // server
-	{SSH_MSG_NEWKEYS, recv_msg_newkeys},
 	{SSH_MSG_CHANNEL_DATA, recv_msg_channel_data},
 	{SSH_MSG_CHANNEL_WINDOW_ADJUST, recv_msg_channel_window_adjust},
+	{SSH_MSG_USERAUTH_REQUEST, recv_msg_userauth_request}, /* server */
+	{SSH_MSG_SERVICE_REQUEST, recv_msg_service_request}, /* server */
+	{SSH_MSG_KEXINIT, recv_msg_kexinit},
+	{SSH_MSG_KEXDH_INIT, recv_msg_kexdh_init}, /* server */
+	{SSH_MSG_NEWKEYS, recv_msg_newkeys},
 	{SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_remotetcp},
 	{SSH_MSG_CHANNEL_REQUEST, recv_msg_channel_request},
 	{SSH_MSG_CHANNEL_OPEN, recv_msg_channel_open},