changeset 1678:4b4cfc92c5b7

Make server send SSH_MSG_EXT_INFO Ensure that only valid hostkey algorithms are sent in the first kex guess
author Matt Johnston <matt@ucc.asn.au>
date Thu, 21 May 2020 23:00:22 +0800
parents e05c0e394f1d
children 90fffce0ee99
files algo.h common-algo.c common-kex.c kex.h svr-kex.c svr-runopts.c
diffstat 6 files changed, 75 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/algo.h	Thu May 21 22:58:56 2020 +0800
+++ b/algo.h	Thu May 21 23:00:22 2020 +0800
@@ -47,7 +47,7 @@
 
 /* lists mapping ssh types of algorithms to internal values */
 extern algo_type sshkex[];
-extern algo_type sshhostkey[];
+extern algo_type sigalgs[];
 extern algo_type sshciphers[];
 extern algo_type sshhashes[];
 extern algo_type ssh_compress[];
@@ -112,11 +112,15 @@
 	const struct ltc_hash_descriptor *hash_desc;
 };
 
+/* Includes all algorithms is useall is set */
+void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall);
+/* Includes "usable" algorithms */
 void buf_put_algolist(buffer * buf, const algo_type localalgos[]);
 
 #define KEXGUESS2_ALGO_NAME "[email protected]"
 
 int buf_has_algo(buffer *buf, const char *algo);
+algo_type * first_usable_algo(algo_type algos[]);
 algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
 		int kexguess2, int *goodguess);
 
--- a/common-algo.c	Thu May 21 22:58:56 2020 +0800
+++ b/common-algo.c	Thu May 21 23:00:22 2020 +0800
@@ -222,7 +222,7 @@
 	{NULL, 0, NULL, 0, NULL}
 };
 
-algo_type sshhostkey[] = {
+algo_type sigalgs[] = {
 #if DROPBEAR_ED25519
 	{"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL},
 #endif
@@ -321,25 +321,34 @@
 };
 
 /* Output a comma separated list of algorithms to a buffer */
-void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
-
+void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall) {
 	unsigned int i, len;
 	unsigned int donefirst = 0;
-	buffer *algolist = NULL;
+	unsigned int startpos;
 
-	algolist = buf_new(300);
+	startpos = buf->pos;
+	/* Placeholder for length */
+	buf_putint(buf, 0); 
 	for (i = 0; localalgos[i].name != NULL; i++) {
-		if (localalgos[i].usable) {
-			if (donefirst)
-				buf_putbyte(algolist, ',');
+		if (localalgos[i].usable || useall) {
+			if (donefirst) {
+				buf_putbyte(buf, ',');
+			}
 			donefirst = 1;
 			len = strlen(localalgos[i].name);
-			buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
+			buf_putbytes(buf, (const unsigned char *) localalgos[i].name, len);
 		}
 	}
-	buf_putstring(buf, (const char*)algolist->data, algolist->len);
-	TRACE(("algolist add '%*s'", algolist->len, algolist->data))
-	buf_free(algolist);
+	/* Fill out the length */
+	len = buf->pos - startpos - 4;
+	buf_setpos(buf, startpos);
+	buf_putint(buf, len);
+	TRACE(("algolist add %d '%*s'", len, len, buf_getptr(buf, len)))
+	buf_incrwritepos(buf, len);
+}
+
+void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
+	buf_put_algolist_all(buf, localalgos, 0);
 }
 
 /* returns a list of pointers into algolist, of null-terminated names.
@@ -408,6 +417,16 @@
 	return ret;
 }
 
+algo_type * first_usable_algo(algo_type algos[]) {
+	int i;
+	for (i = 0; algos[i].name != NULL; i++) {
+		if (algos[i].usable) {
+			return &algos[i];
+		}
+	}
+	return NULL;
+}
+
 /* match the first algorithm in the comma-separated list in buf which is
  * also in localalgos[], or return NULL on failure.
  * (*goodguess) is set to 1 if the preferred client/server algos match,
--- a/common-kex.c	Thu May 21 22:58:56 2020 +0800
+++ b/common-kex.c	Thu May 21 23:00:22 2020 +0800
@@ -65,7 +65,7 @@
 	buf_put_algolist(ses.writepayload, sshkex);
 
 	/* server_host_key_algorithms */
-	buf_put_algolist(ses.writepayload, sshhostkey);
+	buf_put_algolist(ses.writepayload, sigalgs);
 
 	/* encryption_algorithms_client_to_server */
 	buf_put_algolist(ses.writepayload, sshciphers);
@@ -110,8 +110,8 @@
 	ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
 
 	if (ses.send_kex_first_guess) {
-		ses.newkeys->algo_kex = sshkex[0].data;
-		ses.newkeys->algo_signature = sshhostkey[0].val;
+		ses.newkeys->algo_kex = first_usable_algo(sshkex)->data;
+		ses.newkeys->algo_signature = first_usable_algo(sigalgs)->val;
 		ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
 		ses.send_kex_first_guess();
 	}
@@ -834,9 +834,10 @@
 #endif
 
 	/* Determine if SSH_MSG_EXT_INFO messages should be sent.
-	Should be done for the first key exchange. */
-	if (!ses.kexstate.donefirstkex) {
-		if (IS_DROPBEAR_SERVER) {
+	Should be done for the first key exchange. Only required on server side
+    for server-sig-algs */
+	if (IS_DROPBEAR_SERVER) {
+		if (!ses.kexstate.donefirstkex) {
 			if (buf_has_algo(ses.payload, SSH_EXT_INFO_C) == DROPBEAR_SUCCESS) {
 				ses.allow_ext_info = 1;
 			}
@@ -855,7 +856,7 @@
 	ses.newkeys->algo_kex = algo->data;
 
 	/* server_host_key_algorithms */
-	algo = buf_match_algo(ses.payload, sshhostkey, kexguess2, &goodguess);
+	algo = buf_match_algo(ses.payload, sigalgs, kexguess2, &goodguess);
 	allgood &= goodguess;
 	if (algo == NULL) {
 		erralgo = "hostkey";
@@ -866,7 +867,7 @@
 	ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
 
 	/* encryption_algorithms_client_to_server */
-	c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
+	c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
 	if (c2s_cipher_algo == NULL) {
 		erralgo = "enc c->s";
 		goto error;
@@ -874,7 +875,7 @@
 	TRACE(("enc c2s is  %s", c2s_cipher_algo->name))
 
 	/* encryption_algorithms_server_to_client */
-	s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
+	s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
 	if (s2c_cipher_algo == NULL) {
 		erralgo = "enc s->c";
 		goto error;
@@ -882,7 +883,7 @@
 	TRACE(("enc s2c is  %s", s2c_cipher_algo->name))
 
 	/* mac_algorithms_client_to_server */
-	c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
+	c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
 	if (c2s_hash_algo == NULL) {
 		erralgo = "mac c->s";
 		goto error;
@@ -890,7 +891,7 @@
 	TRACE(("hash c2s is  %s", c2s_hash_algo->name))
 
 	/* mac_algorithms_server_to_client */
-	s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
+	s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
 	if (s2c_hash_algo == NULL) {
 		erralgo = "mac s->c";
 		goto error;
@@ -898,7 +899,7 @@
 	TRACE(("hash s2c is  %s", s2c_hash_algo->name))
 
 	/* compression_algorithms_client_to_server */
-	c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
+	c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
 	if (c2s_comp_algo == NULL) {
 		erralgo = "comp c->s";
 		goto error;
@@ -906,7 +907,7 @@
 	TRACE(("hash c2s is  %s", c2s_comp_algo->name))
 
 	/* compression_algorithms_server_to_client */
-	s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
+	s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
 	if (s2c_comp_algo == NULL) {
 		erralgo = "comp s->c";
 		goto error;
--- a/kex.h	Thu May 21 22:58:56 2020 +0800
+++ b/kex.h	Thu May 21 23:00:22 2020 +0800
@@ -61,6 +61,7 @@
 #endif
 
 void recv_msg_kexdh_init(void); /* server */
+void send_msg_ext_info(void); /* server */
 
 void send_msg_kexdh_init(void); /* client */
 void recv_msg_kexdh_reply(void); /* client */
--- a/svr-kex.c	Thu May 21 22:58:56 2020 +0800
+++ b/svr-kex.c	Thu May 21 23:00:22 2020 +0800
@@ -86,6 +86,11 @@
 	}
 
 	send_msg_newkeys();
+
+	if (ses.allow_ext_info) {
+		send_msg_ext_info();
+	}
+
 	ses.requirenext = SSH_MSG_NEWKEYS;
 	TRACE(("leave recv_msg_kexdh_init"))
 }
@@ -242,3 +247,19 @@
 	TRACE(("leave send_msg_kexdh_reply"))
 }
 
+/* Only used for server-sig-algs on the server side */
+void send_msg_ext_info(void) {
+	TRACE(("enter send_msg_ext_info"))
+
+	buf_putbyte(ses.writepayload, SSH_MSG_EXT_INFO);
+	/* nr-extensions */
+	buf_putint(ses.writepayload, 1);
+
+	buf_putstring(ses.writepayload, SSH_SERVER_SIG_ALGS, strlen(SSH_SERVER_SIG_ALGS));
+	buf_put_algolist_all(ses.writepayload, sigalgs, 1);
+	
+	encrypt_packet();
+
+	TRACE(("leave send_msg_ext_info"))
+
+}
--- a/svr-runopts.c	Thu May 21 22:58:56 2020 +0800
+++ b/svr-runopts.c	Thu May 21 23:00:22 2020 +0800
@@ -485,9 +485,9 @@
 static void disablekey(int type) {
 	int i;
 	TRACE(("Disabling key type %d", type))
-	for (i = 0; sshhostkey[i].name != NULL; i++) {
-		if (sshhostkey[i].val == type) {
-			sshhostkey[i].usable = 0;
+	for (i = 0; sigalgs[i].name != NULL; i++) {
+		if (sigalgs[i].val == type) {
+			sigalgs[i].usable = 0;
 			break;
 		}
 	}