summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--algo.h7
-rw-r--r--cli-runopts.c22
-rw-r--r--common-algo.c98
-rw-r--r--common-kex.c41
-rw-r--r--common-runopts.c40
-rw-r--r--options.h3
-rw-r--r--runopts.h8
7 files changed, 208 insertions, 11 deletions
diff --git a/algo.h b/algo.h
index 87e524d..73712c3 100644
--- a/algo.h
+++ b/algo.h
@@ -88,4 +88,11 @@ algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
int *goodguess);
+#ifdef ENABLE_USER_ALGO_LIST
+int check_user_algos(char* user_algo_list, algo_type * algos,
+ const char *algo_desc);
+char * algolist_string(algo_type algos[]);
+#endif
+
+
#endif /* _ALGO_H_ */
diff --git a/cli-runopts.c b/cli-runopts.c
index 44d2b24..140b0cf 100644
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -86,6 +86,10 @@ static void printhelp() {
#ifdef ENABLE_CLI_PROXYCMD
"-J <proxy_program> Use program pipe rather than TCP connection\n"
#endif
+#ifdef ENABLE_USER_ALGO_LIST
+ "-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n"
+ "-m <MAC list> Specify preferred MACs for packet verification (or '-m help')\n"
+#endif
#ifdef DEBUG_TRACE
"-v verbose (compiled with DEBUG_TRACE)\n"
#endif
@@ -149,6 +153,10 @@ void cli_getopts(int argc, char ** argv) {
#ifndef DISABLE_ZLIB
opts.enable_compress = 1;
#endif
+#ifdef ENABLE_USER_ALGO_LIST
+ opts.cipher_list = NULL;
+ opts.mac_list = NULL;
+#endif
/* not yet
opts.ipv4 = 1;
opts.ipv6 = 1;
@@ -283,6 +291,14 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.agent_fwd = 1;
break;
#endif
+#ifdef ENABLE_USER_ALGO_LIST
+ case 'c':
+ next = &opts.cipher_list;
+ break;
+ case 'm':
+ next = &opts.mac_list;
+ break;
+#endif
#ifdef DEBUG_TRACE
case 'v':
debug_trace = 1;
@@ -290,8 +306,10 @@ void cli_getopts(int argc, char ** argv) {
#endif
case 'F':
case 'e':
+#ifndef ENABLE_USER_ALGO_LIST
case 'c':
case 'm':
+#endif
case 'D':
#ifndef ENABLE_CLI_REMOTETCPFWD
case 'R':
@@ -351,6 +369,10 @@ void cli_getopts(int argc, char ** argv) {
/* And now a few sanity checks and setup */
+#ifdef ENABLE_USER_ALGO_LIST
+ parse_ciphers_macs();
+#endif
+
if (host_arg == NULL) {
printhelp();
exit(EXIT_FAILURE);
diff --git a/common-algo.c b/common-algo.c
index acc3964..5ed809b 100644
--- a/common-algo.c
+++ b/common-algo.c
@@ -260,8 +260,6 @@ int have_algo(char* algo, size_t algolen, algo_type algos[]) {
return DROPBEAR_FAILURE;
}
-
-
/* Output a comma separated list of algorithms to a buffer */
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
@@ -282,3 +280,99 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
buf_putstring(buf, algolist->data, algolist->len);
buf_free(algolist);
}
+
+#ifdef ENABLE_USER_ALGO_LIST
+
+char *
+algolist_string(algo_type algos[])
+{
+ char *ret_list;
+ buffer *b = buf_new(200);
+ buf_put_algolist(b, algos);
+ buf_setpos(b, b->len);
+ buf_putbyte(b, '\0');
+ buf_setpos(b, 4);
+ ret_list = m_strdup(buf_getptr(b, b->len - b->pos));
+ buf_free(b);
+ return ret_list;
+}
+
+static int
+check_algo(const char* algo_name, algo_type *algos)
+{
+ algo_type *a;
+ for (a = algos; a->name != NULL; a++)
+ {
+ if (strcmp(a->name, algo_name) == 0)
+ {
+ a->usable = 2;
+ return DROPBEAR_SUCCESS;
+ }
+ }
+
+ return DROPBEAR_FAILURE;
+}
+
+/* helper for check_user_algos */
+static void
+try_add_algo(const char *algo_name, algo_type *algos,
+ const char *algo_desc, char ** out_list, int *num_ret)
+{
+ if (check_algo(algo_name, algos) == DROPBEAR_FAILURE)
+ {
+ dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", algo_name, algo_desc);
+ return;
+ }
+
+ if (*num_ret != 0)
+ {
+ **out_list = ',';
+ (*out_list)++;
+ }
+
+ *out_list += sprintf(*out_list, "%s", algo_name);
+ (*num_ret)++;
+}
+
+/* Checks a user provided comma-separated algorithm list for available
+ * options. Any that are not acceptable are removed in-place. Returns the
+ * number of valid algorithms. */
+int
+check_user_algos(char* user_algo_list, algo_type * algos,
+ const char *algo_desc)
+{
+ /* this has two passes. first we sweep through the given list of
+ * algorithms and mark them as usable=2 in the algo_type[] array... */
+ int num_ret = 0;
+ char *work_list = m_strdup(user_algo_list);
+ char *last_name = work_list;
+ char *out_list = user_algo_list;
+ char *c;
+ for (c = work_list; *c; c++)
+ {
+ if (*c == ',')
+ {
+ *c = '\0';
+ try_add_algo(last_name, algos, algo_desc, &out_list, &num_ret);
+ last_name = c++;
+ }
+ }
+ try_add_algo(last_name, algos, algo_desc, &out_list, &num_ret);
+ m_free(work_list);
+
+ /* ...then we mark anything with usable==1 as usable=0, and
+ * usable==2 as usable=1. */
+ algo_type *a;
+ for (a = algos; a->name != NULL; a++)
+ {
+ if (a->usable == 1)
+ {
+ a->usable = 0;
+ } else if (a->usable == 2)
+ {
+ a->usable = 1;
+ }
+ }
+ return num_ret;
+}
+#endif // ENABLE_USER_ALGO_LIST
diff --git a/common-kex.c b/common-kex.c
index 2b3472b..d4de5cb 100644
--- a/common-kex.c
+++ b/common-kex.c
@@ -106,17 +106,40 @@ void send_msg_kexinit() {
/* server_host_key_algorithms */
buf_put_algolist(ses.writepayload, sshhostkey);
- /* encryption_algorithms_client_to_server */
- buf_put_algolist(ses.writepayload, sshciphers);
-
- /* encryption_algorithms_server_to_client */
- buf_put_algolist(ses.writepayload, sshciphers);
+#ifdef ENABLE_USER_ALGO_LIST
+ if (opts.cipher_list)
+ {
+ /* encryption_algorithms_client_to_server */
+ buf_putbytes(ses.writepayload, opts.cipher_list, strlen(opts.cipher_list));
+ /* encryption_algorithms_server_to_client */
+ buf_putbytes(ses.writepayload, opts.cipher_list, strlen(opts.cipher_list));
+ }
+ else
+#endif
+ {
+ /* encryption_algorithms_client_to_server */
+ buf_put_algolist(ses.writepayload, sshciphers);
+ /* encryption_algorithms_server_to_client */
+ buf_put_algolist(ses.writepayload, sshciphers);
+ }
- /* mac_algorithms_client_to_server */
- buf_put_algolist(ses.writepayload, sshhashes);
+#ifdef ENABLE_USER_ALGO_LIST
+ if (opts.mac_list)
+ {
+ /* mac_algorithms_client_to_server */
+ buf_putbytes(ses.writepayload, opts.mac_list, strlen(opts.mac_list));
+ /* mac_algorithms_server_to_client */
+ buf_putbytes(ses.writepayload, opts.mac_list, strlen(opts.mac_list));
+ }
+ else
+#endif
+ {
+ /* mac_algorithms_client_to_server */
+ buf_put_algolist(ses.writepayload, sshhashes);
+ /* mac_algorithms_server_to_client */
+ buf_put_algolist(ses.writepayload, sshhashes);
+ }
- /* mac_algorithms_server_to_client */
- buf_put_algolist(ses.writepayload, sshhashes);
/* compression_algorithms_client_to_server */
buf_put_algolist(ses.writepayload, ses.compress_algos);
diff --git a/common-runopts.c b/common-runopts.c
index 2de036e..784055a 100644
--- a/common-runopts.c
+++ b/common-runopts.c
@@ -28,6 +28,7 @@
#include "buffer.h"
#include "dbutil.h"
#include "auth.h"
+#include "algo.h"
runopts opts; /* GLOBAL */
@@ -55,3 +56,42 @@ out:
buf_free(buf);
return ret;
}
+
+#ifdef ENABLE_USER_ALGO_LIST
+void
+parse_ciphers_macs()
+{
+ if (opts.cipher_list)
+ {
+ if (strcmp(opts.cipher_list, "help") == 0)
+ {
+ char *ciphers = algolist_string(sshciphers);
+ dropbear_log(LOG_INFO, "Available ciphers:\n%s\n", ciphers);
+ m_free(ciphers);
+ dropbear_exit(".");
+ }
+
+ if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0)
+ {
+ dropbear_exit("No valid ciphers specified for '-c'");
+ }
+ }
+
+ if (opts.mac_list)
+ {
+ if (strcmp(opts.mac_list, "help") == 0)
+ {
+ char *macs = algolist_string(sshhashes);
+ dropbear_log(LOG_INFO, "Available MACs:\n%s\n", macs);
+ m_free(macs);
+ dropbear_exit(".");
+ }
+
+ if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0)
+ {
+ dropbear_exit("No valid MACs specified for '-m'");
+ }
+ }
+}
+#endif
+
diff --git a/options.h b/options.h
index 14dda0c..c0e25f5 100644
--- a/options.h
+++ b/options.h
@@ -80,6 +80,9 @@ much traffic. */
* to a remote TCP-forwarded connection */
#define ENABLE_CLI_NETCAT
+/* Whether to support "-c" and "-m" flags to choose ciphers/MACs at runtime */
+/* #define ENABLE_USER_ALGO_LIST*/
+
/* Encryption - at least one required.
* Protocol RFC requires 3DES and recommends AES128 for interoperability.
* Including multiple keysize variants the same cipher
diff --git a/runopts.h b/runopts.h
index 83b5861..6d1086b 100644
--- a/runopts.h
+++ b/runopts.h
@@ -47,6 +47,10 @@ typedef struct runopts {
int enable_compress;
#endif
+#ifdef ENABLE_USER_ALGO_LIST
+ char *cipher_list;
+ char *mac_list;
+#endif
} runopts;
@@ -148,4 +152,8 @@ typedef struct cli_runopts {
extern cli_runopts cli_opts;
void cli_getopts(int argc, char ** argv);
+#ifdef ENABLE_USER_ALGO_LIST
+void parse_ciphers_macs();
+#endif
+
#endif /* _RUNOPTS_H_ */