diff options
Diffstat (limited to 'kex.c')
-rw-r--r-- | kex.c | 93 |
1 files changed, 86 insertions, 7 deletions
@@ -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 | */ | ||
178 | char * | ||
179 | kex_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 | */ | ||
216 | int | ||
217 | kex_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 */ |
175 | int | 237 | int |
176 | kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) | 238 | kex_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]; |