From 7a854cb1f8ffb4ec8f81b8ec50cc42c165839ff3 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Tue, 3 Aug 2004 15:51:55 +0000
Subject: [PATCH] Improved signkey code

--HG--
extra : convert_revision : fcf64cb4d2e273f80bf8c5f1d2dd00a0f4dc1acf
---
 options.h        |   1 +
 signkey.c        | 124 ++++++++++++++++++++++++++++++++---------------
 signkey.h        |   2 +
 svr-authpubkey.c |  10 +---
 4 files changed, 90 insertions(+), 47 deletions(-)

diff --git a/options.h b/options.h
index 8ed21aba..02f36bcb 100644
--- a/options.h
+++ b/options.h
@@ -227,6 +227,7 @@
 #define DROPBEAR_SIGNKEY_ANY 0
 #define DROPBEAR_SIGNKEY_RSA 1
 #define DROPBEAR_SIGNKEY_DSS 2
+#define DROPBEAR_SIGNKEY_NONE 3
 
 #define DROPBEAR_COMP_NONE 0
 #define DROPBEAR_COMP_ZLIB 1
diff --git a/signkey.c b/signkey.c
index 2fd301f8..ec6ea747 100644
--- a/signkey.c
+++ b/signkey.c
@@ -44,6 +44,46 @@ sign_key * new_sign_key() {
 
 }
 
+/* Returns "ssh-dss" or "ssh-rsa" corresponding to the type. Exits fatally
+ * if the type is invalid */
+const char* signkey_name_from_type(int type, int *namelen) {
+
+#ifdef DROPBEAR_RSA
+	if (type == DROPBEAR_SIGNKEY_RSA) {
+		*namelen = SSH_SIGNKEY_RSA_LEN;
+		return SSH_SIGNKEY_RSA;
+	}
+#endif
+#ifdef DROPBEAR_DSS
+	if (type == DROPBEAR_SIGNKEY_DSS) {
+		*namelen = SSH_SIGNKEY_DSS_LEN;
+		return SSH_SIGNKEY_DSS;
+	}
+#endif
+	dropbear_exit("bad key type %d", type);
+	return NULL; /* notreached */
+}
+
+/* Returns DROPBEAR_SIGNKEY_RSA, DROPBEAR_SIGNKEY_DSS, 
+ * or DROPBEAR_SIGNKEY_NONE */
+int signkey_type_from_name(const char* name, int namelen) {
+
+#ifdef DROPBEAR_RSA
+	if (namelen == SSH_SIGNKEY_RSA_LEN
+			&& memcmp(name, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN) == 0) {
+		return DROPBEAR_SIGNKEY_RSA;
+	}
+#endif
+#ifdef DROPBEAR_DSS
+	if (namelen == SSH_SIGNKEY_DSS_LEN
+			&& memcmp(name, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN) == 0) {
+		return DROPBEAR_SIGNKEY_DSS;
+	}
+#endif
+
+	return DROPBEAR_SIGNKEY_NONE;
+}
+
 /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
  * type should be set by the caller to specify the type to read, and
  * on return is set to the type read (useful when type = _ANY) */
@@ -51,94 +91,100 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
 
 	unsigned char* ident;
 	unsigned int len;
+	int keytype;
+	int ret = DROPBEAR_FAILURE;
 
 	TRACE(("enter buf_get_pub_key"));
 
 	ident = buf_getstring(buf, &len);
+	keytype = signkey_type_from_name(ident, len);
+	m_free(ident);
+
+	if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) {
+		return DROPBEAR_FAILURE;
+	}
+
+	*type = keytype;
 
+	/* Rewind the buffer back before "ssh-rsa" etc */
+	buf_incrpos(buf, -len - 4);
 
 #ifdef DROPBEAR_DSS
-	if (memcmp(ident, SSH_SIGNKEY_DSS, len) == 0
-			&& (*type == DROPBEAR_SIGNKEY_ANY 
-				|| *type == DROPBEAR_SIGNKEY_DSS)) {
-		m_free(ident);
-		buf_setpos(buf, buf->pos - len - 4);
+	if (keytype == DROPBEAR_SIGNKEY_DSS) {
 		dss_key_free(key->dsskey);
 		key->dsskey = (dss_key*)m_malloc(sizeof(dss_key));
-		*type = DROPBEAR_SIGNKEY_DSS;
-		return buf_get_dss_pub_key(buf, key->dsskey);
+		ret = buf_get_dss_pub_key(buf, key->dsskey);
+		if (ret == DROPBEAR_FAILURE) {
+			m_free(key->dsskey);
+		}
 	}
 #endif
 #ifdef DROPBEAR_RSA
-	if (memcmp(ident, SSH_SIGNKEY_RSA, len) == 0
-			&& (*type == DROPBEAR_SIGNKEY_ANY 
-				|| *type == DROPBEAR_SIGNKEY_RSA)) {
-		m_free(ident);
-		buf_setpos(buf, buf->pos - len - 4);
+	if (keytype == DROPBEAR_SIGNKEY_RSA) {
 		rsa_key_free(key->rsakey);
 		key->rsakey = (rsa_key*)m_malloc(sizeof(rsa_key));
-		*type = DROPBEAR_SIGNKEY_RSA;
-		return buf_get_rsa_pub_key(buf, key->rsakey);
+		ret = buf_get_rsa_pub_key(buf, key->rsakey);
+		if (ret == DROPBEAR_FAILURE) {
+			m_free(key->rsakey);
+		}
 	}
 #endif
-	TRACE(("leave buf_get_pub_key: didn't match the type we want (%d versus '%s'len %d)", *type, ident, len));
 
-	m_free(ident);
+	TRACE(("leave buf_get_pub_key"));
 
-	return DROPBEAR_FAILURE;
+	return ret;
 	
 }
 
-/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
-/* type is set to hold the type returned */
+/* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
+ * type should be set by the caller to specify the type to read, and
+ * on return is set to the type read (useful when type = _ANY) */
 int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
 
 	unsigned char* ident;
 	unsigned int len;
-	int ret;
+	int keytype;
+	int ret = DROPBEAR_FAILURE;
 
 	TRACE(("enter buf_get_priv_key"));
+
 	ident = buf_getstring(buf, &len);
+	keytype = signkey_type_from_name(ident, len);
+	m_free(ident);
+
+	if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) {
+		return DROPBEAR_FAILURE;
+	}
+
+	*type = keytype;
+
+	/* Rewind the buffer back before "ssh-rsa" etc */
+	buf_incrpos(buf, -len - 4);
 
 #ifdef DROPBEAR_DSS
-	if (memcmp(ident, SSH_SIGNKEY_DSS, len) == 0
-			&& (*type == DROPBEAR_SIGNKEY_ANY 
-				|| *type == DROPBEAR_SIGNKEY_DSS)) {
-		m_free(ident);
-		buf_setpos(buf, buf->pos - len - 4);
+	if (keytype == DROPBEAR_SIGNKEY_DSS) {
 		dss_key_free(key->dsskey);
 		key->dsskey = (dss_key*)m_malloc(sizeof(dss_key));
 		ret = buf_get_dss_priv_key(buf, key->dsskey);
-		*type = DROPBEAR_SIGNKEY_DSS;
 		if (ret == DROPBEAR_FAILURE) {
 			m_free(key->dsskey);
 		}
-		TRACE(("leave buf_get_priv_key: done get dss"));
-		return ret;
 	}
 #endif
 #ifdef DROPBEAR_RSA
-	if (memcmp(ident, SSH_SIGNKEY_RSA, len) == 0
-			&& (*type == DROPBEAR_SIGNKEY_ANY 
-				|| *type == DROPBEAR_SIGNKEY_RSA)) {
-		m_free(ident);
-		buf_setpos(buf, buf->pos - len - 4);
+	if (keytype == DROPBEAR_SIGNKEY_RSA) {
 		rsa_key_free(key->rsakey);
 		key->rsakey = (rsa_key*)m_malloc(sizeof(rsa_key));
 		ret = buf_get_rsa_priv_key(buf, key->rsakey);
-		*type = DROPBEAR_SIGNKEY_RSA;
 		if (ret == DROPBEAR_FAILURE) {
 			m_free(key->rsakey);
 		}
-		TRACE(("leave buf_get_priv_key: done get rsa"));
-		return ret;
 	}
 #endif
 
-	m_free(ident);
-	
 	TRACE(("leave buf_get_priv_key"));
-	return DROPBEAR_FAILURE;
+
+	return ret;
 	
 }
 
diff --git a/signkey.h b/signkey.h
index 396db7fd..3bd5c58d 100644
--- a/signkey.h
+++ b/signkey.h
@@ -42,6 +42,8 @@ struct SIGN_key {
 typedef struct SIGN_key sign_key;
 
 sign_key * new_sign_key();
+const char* signkey_name_from_type(int type, int *namelen);
+int signkey_type_from_name(const char* name, int namelen);
 int buf_get_pub_key(buffer *buf, sign_key *key, int *type);
 int buf_get_priv_key(buffer* buf, sign_key *key, int *type);
 void buf_put_pub_key(buffer* buf, sign_key *key, int type);
diff --git a/svr-authpubkey.c b/svr-authpubkey.c
index 9c58a8d6..e6cc6067 100644
--- a/svr-authpubkey.c
+++ b/svr-authpubkey.c
@@ -58,7 +58,6 @@ void svr_auth_pubkey() {
 	unsigned char* keyblob;
 	unsigned int keybloblen;
 	buffer * signbuf = NULL;
-	unsigned int sigoffset;
 	sign_key * key = NULL;
 	char* fp = NULL;
 	int type = -1;
@@ -99,14 +98,9 @@ void svr_auth_pubkey() {
 	 * session_id, concatenated with the payload packet up to the signature */
 	signbuf = buf_new(ses.payload->pos + 4 + SHA1_HASH_SIZE);
 	buf_putstring(signbuf, ses.session_id, SHA1_HASH_SIZE);
-	sigoffset = ses.payload->pos;
-	buf_setpos(ses.payload, 0);
-	memcpy(buf_getwriteptr(signbuf, sigoffset),
-			buf_getptr(ses.payload, sigoffset), sigoffset);
-	buf_incrwritepos(signbuf, sigoffset);
-	buf_setpos(ses.payload, sigoffset);
-
+	buf_putbytes(signbuf, ses.payload->data, ses.payload->pos);
 	buf_setpos(signbuf, 0);
+
 	/* ... and finally verify the signature */
 	fp = sign_key_fingerprint(key, type);
 	if (buf_verify(ses.payload, key, buf_getptr(signbuf, signbuf->len),
-- 
GitLab