summaryrefslogtreecommitdiffstats
path: root/crypto/openssh/kex.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/kex.c')
-rw-r--r--crypto/openssh/kex.c93
1 files changed, 86 insertions, 7 deletions
diff --git a/crypto/openssh/kex.c b/crypto/openssh/kex.c
index dbc55ef..5100c66 100644
--- a/crypto/openssh/kex.c
+++ b/crypto/openssh/kex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.c,v 1.106 2015/04/17 13:25:52 djm Exp $ */
+/* $OpenBSD: kex.c,v 1.109 2015/07/30 00:01:34 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
@@ -155,6 +155,68 @@ kex_names_valid(const char *names)
return 1;
}
+/*
+ * Concatenate algorithm names, avoiding duplicates in the process.
+ * Caller must free returned string.
+ */
+char *
+kex_names_cat(const char *a, const char *b)
+{
+ char *ret = NULL, *tmp = NULL, *cp, *p;
+ size_t len;
+
+ if (a == NULL || *a == '\0')
+ return NULL;
+ if (b == NULL || *b == '\0')
+ return strdup(a);
+ if (strlen(b) > 1024*1024)
+ return NULL;
+ len = strlen(a) + strlen(b) + 2;
+ if ((tmp = cp = strdup(b)) == NULL ||
+ (ret = calloc(1, len)) == NULL) {
+ free(tmp);
+ return NULL;
+ }
+ strlcpy(ret, a, len);
+ for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) {
+ if (match_list(ret, p, NULL) != NULL)
+ continue; /* Algorithm already present */
+ if (strlcat(ret, ",", len) >= len ||
+ strlcat(ret, p, len) >= len) {
+ free(tmp);
+ free(ret);
+ return NULL; /* Shouldn't happen */
+ }
+ }
+ free(tmp);
+ return ret;
+}
+
+/*
+ * Assemble a list of algorithms from a default list and a string from a
+ * configuration file. The user-provided string may begin with '+' to
+ * indicate that it should be appended to the default.
+ */
+int
+kex_assemble_names(const char *def, char **list)
+{
+ char *ret;
+
+ if (list == NULL || *list == NULL || **list == '\0') {
+ *list = strdup(def);
+ return 0;
+ }
+ if (**list != '+') {
+ return 0;
+ }
+
+ if ((ret = kex_names_cat(def, *list + 1)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ free(*list);
+ *list = ret;
+ return 0;
+}
+
/* put algorithm proposal into buffer */
int
kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
@@ -448,6 +510,7 @@ kex_free(struct kex *kex)
free(kex->session_id);
free(kex->client_version_string);
free(kex->server_version_string);
+ free(kex->failed_choice);
free(kex);
}
@@ -626,17 +689,26 @@ kex_choose_conf(struct ssh *ssh)
nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
if ((r = choose_enc(&newkeys->enc, cprop[nenc],
- sprop[nenc])) != 0)
+ sprop[nenc])) != 0) {
+ kex->failed_choice = peer[nenc];
+ peer[nenc] = NULL;
goto out;
+ }
authlen = cipher_authlen(newkeys->enc.cipher);
/* ignore mac for authenticated encryption */
if (authlen == 0 &&
(r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
- sprop[nmac])) != 0)
+ sprop[nmac])) != 0) {
+ kex->failed_choice = peer[nmac];
+ peer[nmac] = NULL;
goto out;
+ }
if ((r = choose_comp(&newkeys->comp, cprop[ncomp],
- sprop[ncomp])) != 0)
+ sprop[ncomp])) != 0) {
+ kex->failed_choice = peer[ncomp];
+ peer[ncomp] = NULL;
goto out;
+ }
debug("kex: %s %s %s %s",
ctos ? "client->server" : "server->client",
newkeys->enc.name,
@@ -644,10 +716,17 @@ kex_choose_conf(struct ssh *ssh)
newkeys->comp.name);
}
if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
- sprop[PROPOSAL_KEX_ALGS])) != 0 ||
- (r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
- sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0)
+ sprop[PROPOSAL_KEX_ALGS])) != 0) {
+ kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
+ peer[PROPOSAL_KEX_ALGS] = NULL;
goto out;
+ }
+ if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
+ sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
+ kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
+ peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
+ goto out;
+ }
need = dh_need = 0;
for (mode = 0; mode < MODE_MAX; mode++) {
newkeys = kex->newkeys[mode];
OpenPOWER on IntegriCloud