changeset 552:de3653483ac0 agent-client

- Client auth using an agent's key works. Still need to implement client agent forwarding.
author Matt Johnston <matt@ucc.asn.au>
date Mon, 06 Jul 2009 14:02:45 +0000
parents c3f2ec71e3d4
children 7f66b8e40f2d
files auth.h cli-agentfwd.c cli-auth.c cli-authpubkey.c runopts.h
diffstat 5 files changed, 90 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/auth.h	Mon Jul 06 12:59:13 2009 +0000
+++ b/auth.h	Mon Jul 06 14:02:45 2009 +0000
@@ -74,6 +74,7 @@
 int cli_auth_pubkey();
 void cli_auth_interactive();
 char* getpass_or_cancel(char* prompt);
+void cli_auth_pubkey_cleanup();
 
 
 #define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
--- a/cli-agentfwd.c	Mon Jul 06 12:59:13 2009 +0000
+++ b/cli-agentfwd.c	Mon Jul 06 14:02:45 2009 +0000
@@ -102,17 +102,26 @@
    data        Any data, depending on packet type.  Encoding as in the ssh packet
                protocol.
 */
-static buffer * agent_request(int fd, unsigned char type) {
+static buffer * agent_request(unsigned char type, buffer *data) {
 
 	buffer * payload = NULL;
 	buffer * inbuf = NULL;
 	size_t readlen = 0;
 	ssize_t ret;
-
-	payload = buf_new(4 + 1);
+	const int fd = cli_opts.agent_fd;
+	unsigned int data_len = 0;
+	if (data)
+	{
+		data_len = data->len;
+	}
 
-	buf_putint(payload, 1);
+	payload = buf_new(4 + 1 + data_len);
+
+	buf_putint(payload, 1 + data_len);
 	buf_putbyte(payload, type);
+	if (data) {
+		buf_putbytes(payload, data->data, data->len);
+	}
 	buf_setpos(payload, 0);
 
 	ret = atomicio(write, fd, buf_getptr(payload, payload->len), payload->len);
@@ -160,7 +169,7 @@
 	return inbuf;
 }
 
-static void agent_get_key_list(int fd, m_list * ret_list)
+static void agent_get_key_list(m_list * ret_list)
 {
 	buffer * inbuf = NULL;
 	unsigned int num = 0;
@@ -168,9 +177,9 @@
 	unsigned int i;
 	int ret;
 
-	inbuf = agent_request(fd, SSH2_AGENTC_REQUEST_IDENTITIES);
+	inbuf = agent_request(SSH2_AGENTC_REQUEST_IDENTITIES, NULL);
 	if (!inbuf) {
-		TRACE(("agent_request returned no identities"))
+		TRACE(("agent_request failed returning identities"))
 		goto out;
 	}
 
@@ -191,7 +200,6 @@
 		sign_key * pubkey = NULL;
 		int key_type = DROPBEAR_SIGNKEY_ANY;
 		buffer * key_buf;
-		struct SignKeyList *nextkey = NULL;
 
 		/* each public key is encoded as a string */
 		key_buf = buf_getstringbuf(inbuf);
@@ -222,19 +230,66 @@
    be updated. */
 void load_agent_keys(m_list *ret_list)
 {
-	int fd;
-	fd = connect_agent();
-	if (fd < 0) {
+	/* agent_fd will be closed after successful auth */
+	cli_opts.agent_fd = connect_agent();
+	if (cli_opts.agent_fd < 0) {
 		dropbear_log(LOG_INFO, "Failed to connect to agent");
 		return;
 	}
 
-	agent_get_key_list(fd, ret_list);
-	close(fd);
+	agent_get_key_list(ret_list);
 }
 
 void agent_buf_sign(buffer *sigblob, sign_key *key, 
 		const unsigned char *data, unsigned int len) {
+	buffer *request_data = buf_new(MAX_PUBKEY_SIZE + len + 12);
+	buffer *response;
+	unsigned int keylen, siglen;
+	int packet_type;
+	
+	/* Request format
+	byte			SSH2_AGENTC_SIGN_REQUEST
+	string			key_blob
+	string			data
+	uint32			flags
+	*/
+	/* We write the key, then figure how long it was and write that */
+	//buf_putint(request_data, 0);
+	buf_put_pub_key(request_data, key, key->type);
+	keylen = request_data->len - 4;
+	//buf_setpos(request_data, 0);
+	//buf_putint(request_data, keylen);
+	
+	//buf_setpos(request_data, request_data->len);
+	buf_putstring(request_data, data, len);
+	buf_putint(request_data, 0);
+	
+	response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
+	buf_free(request_data);
+	
+	if (!response) {
+		goto fail;
+	}
+	
+	packet_type = buf_getbyte(response);
+	if (packet_type != SSH2_AGENT_SIGN_RESPONSE) {
+		goto fail;
+	}
+	
+	/* Response format
+	byte			SSH2_AGENT_SIGN_RESPONSE
+	string			signature_blob
+	*/
+	siglen = buf_getint(response);
+	buf_putbytes(sigblob, buf_getptr(response, siglen), siglen);
+	buf_free(response);
+	
+	return;
+fail:
+	/* XXX don't fail badly here. instead propagate a failure code back up to
+	   the cli auth pubkey code, and just remove this key from the list of 
+	   ones to try. */
+	dropbear_exit("Agent failed signing key");
 }
 
 #endif
--- a/cli-auth.c	Mon Jul 06 12:59:13 2009 +0000
+++ b/cli-auth.c	Mon Jul 06 14:02:45 2009 +0000
@@ -234,6 +234,10 @@
 	ses.authstate.authdone = 1;
 	cli_ses.state = USERAUTH_SUCCESS_RCVD;
 	cli_ses.lastauthtype = AUTH_TYPE_NONE;
+
+#ifdef ENABLE_CLI_PUBKEY_AUTH
+	cli_auth_pubkey_cleanup();
+#endif
 }
 
 void cli_auth_try() {
--- a/cli-authpubkey.c	Mon Jul 06 12:59:13 2009 +0000
+++ b/cli-authpubkey.c	Mon Jul 06 14:02:45 2009 +0000
@@ -174,7 +174,7 @@
 		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);
+		cli_buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
 		buf_free(sigbuf); /* Nothing confidential in the buffer */
 	}
 
@@ -202,8 +202,22 @@
 		TRACE(("leave cli_auth_pubkey-success"))
 		return 1;
 	} else {
+		/* no more keys left */
 		TRACE(("leave cli_auth_pubkey-failure"))
 		return 0;
 	}
 }
+
+void cli_auth_pubkey_cleanup() {
+
+#ifdef ENABLE_CLI_AGENTFWD
+	m_close(cli_opts.agent_fd);
+	cli_opts.agent_fd = -1;
+#endif
+
+	while (cli_opts.privkeys->first) {
+		sign_key * key = list_remove(cli_opts.privkeys->first);
+		sign_key_free(key);
+	}
+}
 #endif /* Pubkey auth */
--- a/runopts.h	Mon Jul 06 12:59:13 2009 +0000
+++ b/runopts.h	Mon Jul 06 14:02:45 2009 +0000
@@ -124,6 +124,8 @@
 	int agent_fwd;
 	int agent_keys_loaded; /* whether pubkeys has been populated with a 
 							  list of keys held by the agent */
+	int agent_fd; /* The agent fd is only set during authentication. Forwarded
+	                 agent sessions have their own file descriptors */
 #endif
 
 #ifdef ENABLE_CLI_NETCAT