summaryrefslogtreecommitdiff
path: root/kex.c
diff options
context:
space:
mode:
Diffstat (limited to 'kex.c')
-rw-r--r--kex.c93
1 files changed, 86 insertions, 7 deletions
diff --git a/kex.c b/kex.c
index 4d8e6f536..39a6f98c4 100644
--- a/kex.c
+++ b/kex.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kex.c,v 1.106 2015/04/17 13:25:52 djm Exp $ */ 1/* $OpenBSD: kex.c,v 1.109 2015/07/30 00:01:34 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -171,6 +171,68 @@ kex_names_valid(const char *names)
171 return 1; 171 return 1;
172} 172}
173 173
174/*
175 * Concatenate algorithm names, avoiding duplicates in the process.
176 * Caller must free returned string.
177 */
178char *
179kex_names_cat(const char *a, const char *b)
180{
181 char *ret = NULL, *tmp = NULL, *cp, *p;
182 size_t len;
183
184 if (a == NULL || *a == '\0')
185 return NULL;
186 if (b == NULL || *b == '\0')
187 return strdup(a);
188 if (strlen(b) > 1024*1024)
189 return NULL;
190 len = strlen(a) + strlen(b) + 2;
191 if ((tmp = cp = strdup(b)) == NULL ||
192 (ret = calloc(1, len)) == NULL) {
193 free(tmp);
194 return NULL;
195 }
196 strlcpy(ret, a, len);
197 for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) {
198 if (match_list(ret, p, NULL) != NULL)
199 continue; /* Algorithm already present */
200 if (strlcat(ret, ",", len) >= len ||
201 strlcat(ret, p, len) >= len) {
202 free(tmp);
203 free(ret);
204 return NULL; /* Shouldn't happen */
205 }
206 }
207 free(tmp);
208 return ret;
209}
210
211/*
212 * Assemble a list of algorithms from a default list and a string from a
213 * configuration file. The user-provided string may begin with '+' to
214 * indicate that it should be appended to the default.
215 */
216int
217kex_assemble_names(const char *def, char **list)
218{
219 char *ret;
220
221 if (list == NULL || *list == NULL || **list == '\0') {
222 *list = strdup(def);
223 return 0;
224 }
225 if (**list != '+') {
226 return 0;
227 }
228
229 if ((ret = kex_names_cat(def, *list + 1)) == NULL)
230 return SSH_ERR_ALLOC_FAIL;
231 free(*list);
232 *list = ret;
233 return 0;
234}
235
174/* put algorithm proposal into buffer */ 236/* put algorithm proposal into buffer */
175int 237int
176kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) 238kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
@@ -464,6 +526,7 @@ kex_free(struct kex *kex)
464 free(kex->session_id); 526 free(kex->session_id);
465 free(kex->client_version_string); 527 free(kex->client_version_string);
466 free(kex->server_version_string); 528 free(kex->server_version_string);
529 free(kex->failed_choice);
467 free(kex); 530 free(kex);
468} 531}
469 532
@@ -642,17 +705,26 @@ kex_choose_conf(struct ssh *ssh)
642 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; 705 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
643 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; 706 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
644 if ((r = choose_enc(&newkeys->enc, cprop[nenc], 707 if ((r = choose_enc(&newkeys->enc, cprop[nenc],
645 sprop[nenc])) != 0) 708 sprop[nenc])) != 0) {
709 kex->failed_choice = peer[nenc];
710 peer[nenc] = NULL;
646 goto out; 711 goto out;
712 }
647 authlen = cipher_authlen(newkeys->enc.cipher); 713 authlen = cipher_authlen(newkeys->enc.cipher);
648 /* ignore mac for authenticated encryption */ 714 /* ignore mac for authenticated encryption */
649 if (authlen == 0 && 715 if (authlen == 0 &&
650 (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], 716 (r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
651 sprop[nmac])) != 0) 717 sprop[nmac])) != 0) {
718 kex->failed_choice = peer[nmac];
719 peer[nmac] = NULL;
652 goto out; 720 goto out;
721 }
653 if ((r = choose_comp(&newkeys->comp, cprop[ncomp], 722 if ((r = choose_comp(&newkeys->comp, cprop[ncomp],
654 sprop[ncomp])) != 0) 723 sprop[ncomp])) != 0) {
724 kex->failed_choice = peer[ncomp];
725 peer[ncomp] = NULL;
655 goto out; 726 goto out;
727 }
656 debug("kex: %s %s %s %s", 728 debug("kex: %s %s %s %s",
657 ctos ? "client->server" : "server->client", 729 ctos ? "client->server" : "server->client",
658 newkeys->enc.name, 730 newkeys->enc.name,
@@ -660,10 +732,17 @@ kex_choose_conf(struct ssh *ssh)
660 newkeys->comp.name); 732 newkeys->comp.name);
661 } 733 }
662 if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], 734 if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
663 sprop[PROPOSAL_KEX_ALGS])) != 0 || 735 sprop[PROPOSAL_KEX_ALGS])) != 0) {
664 (r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], 736 kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
665 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) 737 peer[PROPOSAL_KEX_ALGS] = NULL;
666 goto out; 738 goto out;
739 }
740 if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
741 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
742 kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
743 peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
744 goto out;
745 }
667 need = dh_need = 0; 746 need = dh_need = 0;
668 for (mode = 0; mode < MODE_MAX; mode++) { 747 for (mode = 0; mode < MODE_MAX; mode++) {
669 newkeys = kex->newkeys[mode]; 748 newkeys = kex->newkeys[mode];