summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2020-05-21 23:00:22 +0800
committerMatt Johnston <matt@ucc.asn.au>2020-05-21 23:00:22 +0800
commit331d4a714f65772e384e15ff55b850a6e9e6786b (patch)
tree16c000a69313d6f49610d48af4c74d6d07d1d899
parent2a81289ed32d9e1ca612a41975974bfa258d2ace (diff)
Make server send SSH_MSG_EXT_INFO
Ensure that only valid hostkey algorithms are sent in the first kex guess
-rw-r--r--algo.h6
-rw-r--r--common-algo.c43
-rw-r--r--common-kex.c27
-rw-r--r--kex.h1
-rw-r--r--svr-kex.c21
-rw-r--r--svr-runopts.c6
6 files changed, 75 insertions, 29 deletions
diff --git a/algo.h b/algo.h
index 1565665..6f6da34 100644
--- a/algo.h
+++ b/algo.h
@@ -47,7 +47,7 @@ typedef struct Algo_Type algo_type;
/* 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 @@ struct dropbear_kex {
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 "kexguess2@matt.ucc.asn.au"
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);
diff --git a/common-algo.c b/common-algo.c
index 938695d..54bc559 100644
--- a/common-algo.c
+++ b/common-algo.c
@@ -222,7 +222,7 @@ algo_type ssh_nocompress[] = {
{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 @@ algo_type sshkex[] = {
};
/* 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 @@ int buf_has_algo(buffer *buf, const char *algo) {
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,
diff --git a/common-kex.c b/common-kex.c
index 8172796..7063c81 100644
--- a/common-kex.c
+++ b/common-kex.c
@@ -65,7 +65,7 @@ void send_msg_kexinit() {
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 @@ void send_msg_kexinit() {
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 @@ static void read_kex_algos() {
#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 @@ static void read_kex_algos() {
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 @@ static void read_kex_algos() {
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 @@ static void read_kex_algos() {
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 @@ static void read_kex_algos() {
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 @@ static void read_kex_algos() {
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 @@ static void read_kex_algos() {
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 @@ static void read_kex_algos() {
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;
diff --git a/kex.h b/kex.h
index 3b0ec62..cdec673 100644
--- a/kex.h
+++ b/kex.h
@@ -61,6 +61,7 @@ int is_compress_recv(void);
#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 */
diff --git a/svr-kex.c b/svr-kex.c
index e3e63d0..44e10ff 100644
--- a/svr-kex.c
+++ b/svr-kex.c
@@ -86,6 +86,11 @@ void recv_msg_kexdh_init() {
}
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 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) {
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"))
+
+}
diff --git a/svr-runopts.c b/svr-runopts.c
index d430825..770f70a 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -485,9 +485,9 @@ static void addportandaddress(const char* spec) {
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;
}
}