diff options
-rw-r--r-- | kex.c | 57 |
1 files changed, 38 insertions, 19 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.c,v 1.109 2015/07/30 00:01:34 djm Exp $ */ | 1 | /* $OpenBSD: kex.c,v 1.110 2015/08/21 23:57:48 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 | * |
@@ -67,6 +67,19 @@ extern const EVP_MD *evp_ssh_sha256(void); | |||
67 | static int kex_choose_conf(struct ssh *); | 67 | static int kex_choose_conf(struct ssh *); |
68 | static int kex_input_newkeys(int, u_int32_t, void *); | 68 | static int kex_input_newkeys(int, u_int32_t, void *); |
69 | 69 | ||
70 | static const char *proposal_names[PROPOSAL_MAX] = { | ||
71 | "KEX algorithms", | ||
72 | "host key algorithms", | ||
73 | "ciphers ctos", | ||
74 | "ciphers stoc", | ||
75 | "MACs ctos", | ||
76 | "MACs stoc", | ||
77 | "compression ctos", | ||
78 | "compression stoc", | ||
79 | "languages ctos", | ||
80 | "languages stoc", | ||
81 | }; | ||
82 | |||
70 | struct kexalg { | 83 | struct kexalg { |
71 | char *name; | 84 | char *name; |
72 | u_int type; | 85 | u_int type; |
@@ -267,7 +280,7 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) | |||
267 | for (i = 0; i < PROPOSAL_MAX; i++) { | 280 | for (i = 0; i < PROPOSAL_MAX; i++) { |
268 | if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) | 281 | if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) |
269 | goto out; | 282 | goto out; |
270 | debug2("kex_parse_kexinit: %s", proposal[i]); | 283 | debug2("%s: %s", proposal_names[i], proposal[i]); |
271 | } | 284 | } |
272 | /* first kex follows / reserved */ | 285 | /* first kex follows / reserved */ |
273 | if ((r = sshbuf_get_u8(b, &v)) != 0 || | 286 | if ((r = sshbuf_get_u8(b, &v)) != 0 || |
@@ -275,8 +288,8 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) | |||
275 | goto out; | 288 | goto out; |
276 | if (first_kex_follows != NULL) | 289 | if (first_kex_follows != NULL) |
277 | *first_kex_follows = i; | 290 | *first_kex_follows = i; |
278 | debug2("kex_parse_kexinit: first_kex_follows %d ", v); | 291 | debug2("first_kex_follows %d ", v); |
279 | debug2("kex_parse_kexinit: reserved %u ", i); | 292 | debug2("reserved %u ", i); |
280 | r = 0; | 293 | r = 0; |
281 | *propp = proposal; | 294 | *propp = proposal; |
282 | out: | 295 | out: |
@@ -593,6 +606,7 @@ choose_kex(struct kex *k, char *client, char *server) | |||
593 | 606 | ||
594 | k->name = match_list(client, server, NULL); | 607 | k->name = match_list(client, server, NULL); |
595 | 608 | ||
609 | debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); | ||
596 | if (k->name == NULL) | 610 | if (k->name == NULL) |
597 | return SSH_ERR_NO_KEX_ALG_MATCH; | 611 | return SSH_ERR_NO_KEX_ALG_MATCH; |
598 | if ((kexalg = kex_alg_by_name(k->name)) == NULL) | 612 | if ((kexalg = kex_alg_by_name(k->name)) == NULL) |
@@ -608,6 +622,8 @@ choose_hostkeyalg(struct kex *k, char *client, char *server) | |||
608 | { | 622 | { |
609 | char *hostkeyalg = match_list(client, server, NULL); | 623 | char *hostkeyalg = match_list(client, server, NULL); |
610 | 624 | ||
625 | debug("kex: host key algorithm: %s", | ||
626 | hostkeyalg ? hostkeyalg : "(no match)"); | ||
611 | if (hostkeyalg == NULL) | 627 | if (hostkeyalg == NULL) |
612 | return SSH_ERR_NO_HOSTKEY_ALG_MATCH; | 628 | return SSH_ERR_NO_HOSTKEY_ALG_MATCH; |
613 | k->hostkey_type = sshkey_type_from_name(hostkeyalg); | 629 | k->hostkey_type = sshkey_type_from_name(hostkeyalg); |
@@ -653,8 +669,11 @@ kex_choose_conf(struct ssh *ssh) | |||
653 | u_int mode, ctos, need, dh_need, authlen; | 669 | u_int mode, ctos, need, dh_need, authlen; |
654 | int r, first_kex_follows; | 670 | int r, first_kex_follows; |
655 | 671 | ||
656 | if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 || | 672 | debug2("local %s KEXINIT proposal", kex->server ? "server" : "client"); |
657 | (r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) | 673 | if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0) |
674 | goto out; | ||
675 | debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server"); | ||
676 | if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) | ||
658 | goto out; | 677 | goto out; |
659 | 678 | ||
660 | if (kex->server) { | 679 | if (kex->server) { |
@@ -677,6 +696,18 @@ kex_choose_conf(struct ssh *ssh) | |||
677 | } | 696 | } |
678 | 697 | ||
679 | /* Algorithm Negotiation */ | 698 | /* Algorithm Negotiation */ |
699 | if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], | ||
700 | sprop[PROPOSAL_KEX_ALGS])) != 0) { | ||
701 | kex->failed_choice = peer[PROPOSAL_KEX_ALGS]; | ||
702 | peer[PROPOSAL_KEX_ALGS] = NULL; | ||
703 | goto out; | ||
704 | } | ||
705 | if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
706 | sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) { | ||
707 | kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
708 | peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL; | ||
709 | goto out; | ||
710 | } | ||
680 | for (mode = 0; mode < MODE_MAX; mode++) { | 711 | for (mode = 0; mode < MODE_MAX; mode++) { |
681 | if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { | 712 | if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { |
682 | r = SSH_ERR_ALLOC_FAIL; | 713 | r = SSH_ERR_ALLOC_FAIL; |
@@ -709,24 +740,12 @@ kex_choose_conf(struct ssh *ssh) | |||
709 | peer[ncomp] = NULL; | 740 | peer[ncomp] = NULL; |
710 | goto out; | 741 | goto out; |
711 | } | 742 | } |
712 | debug("kex: %s %s %s %s", | 743 | debug("kex: %s cipher: %s MAC: %s compression: %s", |
713 | ctos ? "client->server" : "server->client", | 744 | ctos ? "client->server" : "server->client", |
714 | newkeys->enc.name, | 745 | newkeys->enc.name, |
715 | authlen == 0 ? newkeys->mac.name : "<implicit>", | 746 | authlen == 0 ? newkeys->mac.name : "<implicit>", |
716 | newkeys->comp.name); | 747 | newkeys->comp.name); |
717 | } | 748 | } |
718 | if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], | ||
719 | sprop[PROPOSAL_KEX_ALGS])) != 0) { | ||
720 | kex->failed_choice = peer[PROPOSAL_KEX_ALGS]; | ||
721 | peer[PROPOSAL_KEX_ALGS] = NULL; | ||
722 | goto out; | ||
723 | } | ||
724 | if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
725 | sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) { | ||
726 | kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
727 | peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL; | ||
728 | goto out; | ||
729 | } | ||
730 | need = dh_need = 0; | 749 | need = dh_need = 0; |
731 | for (mode = 0; mode < MODE_MAX; mode++) { | 750 | for (mode = 0; mode < MODE_MAX; mode++) { |
732 | newkeys = kex->newkeys[mode]; | 751 | newkeys = kex->newkeys[mode]; |