summaryrefslogtreecommitdiff
path: root/kex.c
diff options
context:
space:
mode:
Diffstat (limited to 'kex.c')
-rw-r--r--kex.c168
1 files changed, 134 insertions, 34 deletions
diff --git a/kex.c b/kex.c
index 390bb694d..913e92392 100644
--- a/kex.c
+++ b/kex.c
@@ -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.117 2016/02/08 10:57:07 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 *
@@ -49,7 +49,6 @@
49#include "misc.h" 49#include "misc.h"
50#include "dispatch.h" 50#include "dispatch.h"
51#include "monitor.h" 51#include "monitor.h"
52#include "roaming.h"
53 52
54#include "ssherr.h" 53#include "ssherr.h"
55#include "sshbuf.h" 54#include "sshbuf.h"
@@ -71,6 +70,19 @@ extern const EVP_MD *evp_ssh_sha256(void);
71static int kex_choose_conf(struct ssh *); 70static int kex_choose_conf(struct ssh *);
72static int kex_input_newkeys(int, u_int32_t, void *); 71static int kex_input_newkeys(int, u_int32_t, void *);
73 72
73static const char *proposal_names[PROPOSAL_MAX] = {
74 "KEX algorithms",
75 "host key algorithms",
76 "ciphers ctos",
77 "ciphers stoc",
78 "MACs ctos",
79 "MACs stoc",
80 "compression ctos",
81 "compression stoc",
82 "languages ctos",
83 "languages stoc",
84};
85
74struct kexalg { 86struct kexalg {
75 char *name; 87 char *name;
76 u_int type; 88 u_int type;
@@ -283,7 +295,7 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
283 for (i = 0; i < PROPOSAL_MAX; i++) { 295 for (i = 0; i < PROPOSAL_MAX; i++) {
284 if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) 296 if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0)
285 goto out; 297 goto out;
286 debug2("kex_parse_kexinit: %s", proposal[i]); 298 debug2("%s: %s", proposal_names[i], proposal[i]);
287 } 299 }
288 /* first kex follows / reserved */ 300 /* first kex follows / reserved */
289 if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ 301 if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */
@@ -318,7 +330,14 @@ kex_prop_free(char **proposal)
318static int 330static int
319kex_protocol_error(int type, u_int32_t seq, void *ctxt) 331kex_protocol_error(int type, u_int32_t seq, void *ctxt)
320{ 332{
321 error("Hm, kex protocol error: type %d seq %u", type, seq); 333 struct ssh *ssh = active_state; /* XXX */
334 int r;
335
336 error("kex protocol error: type %d seq %u", type, seq);
337 if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
338 (r = sshpkt_put_u32(ssh, seq)) != 0 ||
339 (r = sshpkt_send(ssh)) != 0)
340 return r;
322 return 0; 341 return 0;
323} 342}
324 343
@@ -330,6 +349,20 @@ kex_reset_dispatch(struct ssh *ssh)
330 ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); 349 ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
331} 350}
332 351
352static int
353kex_send_ext_info(struct ssh *ssh)
354{
355 int r;
356
357 if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
358 (r = sshpkt_put_u32(ssh, 1)) != 0 ||
359 (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
360 (r = sshpkt_put_cstring(ssh, "rsa-sha2-256,rsa-sha2-512")) != 0 ||
361 (r = sshpkt_send(ssh)) != 0)
362 return r;
363 return 0;
364}
365
333int 366int
334kex_send_newkeys(struct ssh *ssh) 367kex_send_newkeys(struct ssh *ssh)
335{ 368{
@@ -342,9 +375,51 @@ kex_send_newkeys(struct ssh *ssh)
342 debug("SSH2_MSG_NEWKEYS sent"); 375 debug("SSH2_MSG_NEWKEYS sent");
343 debug("expecting SSH2_MSG_NEWKEYS"); 376 debug("expecting SSH2_MSG_NEWKEYS");
344 ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); 377 ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
378 if (ssh->kex->ext_info_c)
379 if ((r = kex_send_ext_info(ssh)) != 0)
380 return r;
345 return 0; 381 return 0;
346} 382}
347 383
384int
385kex_input_ext_info(int type, u_int32_t seq, void *ctxt)
386{
387 struct ssh *ssh = ctxt;
388 struct kex *kex = ssh->kex;
389 u_int32_t i, ninfo;
390 char *name, *val, *found;
391 int r;
392
393 debug("SSH2_MSG_EXT_INFO received");
394 ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
395 if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0)
396 return r;
397 for (i = 0; i < ninfo; i++) {
398 if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
399 return r;
400 if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) {
401 free(name);
402 return r;
403 }
404 debug("%s: %s=<%s>", __func__, name, val);
405 if (strcmp(name, "server-sig-algs") == 0) {
406 found = match_list("rsa-sha2-256", val, NULL);
407 if (found) {
408 kex->rsa_sha2 = 256;
409 free(found);
410 }
411 found = match_list("rsa-sha2-512", val, NULL);
412 if (found) {
413 kex->rsa_sha2 = 512;
414 free(found);
415 }
416 }
417 free(name);
418 free(val);
419 }
420 return sshpkt_get_end(ssh);
421}
422
348static int 423static int
349kex_input_newkeys(int type, u_int32_t seq, void *ctxt) 424kex_input_newkeys(int type, u_int32_t seq, void *ctxt)
350{ 425{
@@ -484,7 +559,7 @@ kex_free_newkeys(struct newkeys *newkeys)
484 newkeys->enc.key = NULL; 559 newkeys->enc.key = NULL;
485 } 560 }
486 if (newkeys->enc.iv) { 561 if (newkeys->enc.iv) {
487 explicit_bzero(newkeys->enc.iv, newkeys->enc.block_size); 562 explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len);
488 free(newkeys->enc.iv); 563 free(newkeys->enc.iv);
489 newkeys->enc.iv = NULL; 564 newkeys->enc.iv = NULL;
490 } 565 }
@@ -527,6 +602,8 @@ kex_free(struct kex *kex)
527 free(kex->client_version_string); 602 free(kex->client_version_string);
528 free(kex->server_version_string); 603 free(kex->server_version_string);
529 free(kex->failed_choice); 604 free(kex->failed_choice);
605 free(kex->hostkey_alg);
606 free(kex->name);
530 free(kex); 607 free(kex);
531} 608}
532 609
@@ -545,6 +622,25 @@ kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX])
545 return 0; 622 return 0;
546} 623}
547 624
625/*
626 * Request key re-exchange, returns 0 on success or a ssherr.h error
627 * code otherwise. Must not be called if KEX is incomplete or in-progress.
628 */
629int
630kex_start_rekex(struct ssh *ssh)
631{
632 if (ssh->kex == NULL) {
633 error("%s: no kex", __func__);
634 return SSH_ERR_INTERNAL_ERROR;
635 }
636 if (ssh->kex->done == 0) {
637 error("%s: requested twice", __func__);
638 return SSH_ERR_INTERNAL_ERROR;
639 }
640 ssh->kex->done = 0;
641 return kex_send_kexinit(ssh);
642}
643
548static int 644static int
549choose_enc(struct sshenc *enc, char *client, char *server) 645choose_enc(struct sshenc *enc, char *client, char *server)
550{ 646{
@@ -609,6 +705,7 @@ choose_kex(struct kex *k, char *client, char *server)
609 705
610 k->name = match_list(client, server, NULL); 706 k->name = match_list(client, server, NULL);
611 707
708 debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
612 if (k->name == NULL) 709 if (k->name == NULL)
613 return SSH_ERR_NO_KEX_ALG_MATCH; 710 return SSH_ERR_NO_KEX_ALG_MATCH;
614 if ((kexalg = kex_alg_by_name(k->name)) == NULL) 711 if ((kexalg = kex_alg_by_name(k->name)) == NULL)
@@ -622,15 +719,16 @@ choose_kex(struct kex *k, char *client, char *server)
622static int 719static int
623choose_hostkeyalg(struct kex *k, char *client, char *server) 720choose_hostkeyalg(struct kex *k, char *client, char *server)
624{ 721{
625 char *hostkeyalg = match_list(client, server, NULL); 722 k->hostkey_alg = match_list(client, server, NULL);
626 723
627 if (hostkeyalg == NULL) 724 debug("kex: host key algorithm: %s",
725 k->hostkey_alg ? k->hostkey_alg : "(no match)");
726 if (k->hostkey_alg == NULL)
628 return SSH_ERR_NO_HOSTKEY_ALG_MATCH; 727 return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
629 k->hostkey_type = sshkey_type_from_name(hostkeyalg); 728 k->hostkey_type = sshkey_type_from_name(k->hostkey_alg);
630 if (k->hostkey_type == KEY_UNSPEC) 729 if (k->hostkey_type == KEY_UNSPEC)
631 return SSH_ERR_INTERNAL_ERROR; 730 return SSH_ERR_INTERNAL_ERROR;
632 k->hostkey_nid = sshkey_ecdsa_nid_from_name(hostkeyalg); 731 k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg);
633 free(hostkeyalg);
634 return 0; 732 return 0;
635} 733}
636 734
@@ -669,8 +767,11 @@ kex_choose_conf(struct ssh *ssh)
669 u_int mode, ctos, need, dh_need, authlen; 767 u_int mode, ctos, need, dh_need, authlen;
670 int r, first_kex_follows; 768 int r, first_kex_follows;
671 769
672 if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 || 770 debug2("local %s KEXINIT proposal", kex->server ? "server" : "client");
673 (r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) 771 if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0)
772 goto out;
773 debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server");
774 if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0)
674 goto out; 775 goto out;
675 776
676 if (kex->server) { 777 if (kex->server) {
@@ -681,18 +782,30 @@ kex_choose_conf(struct ssh *ssh)
681 sprop=peer; 782 sprop=peer;
682 } 783 }
683 784
684 /* Check whether server offers roaming */ 785 /* Check whether client supports ext_info_c */
685 if (!kex->server) { 786 if (kex->server) {
686 char *roaming = match_list(KEX_RESUME, 787 char *ext;
687 peer[PROPOSAL_KEX_ALGS], NULL);
688 788
689 if (roaming) { 789 ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL);
690 kex->roaming = 1; 790 if (ext) {
691 free(roaming); 791 kex->ext_info_c = 1;
792 free(ext);
692 } 793 }
693 } 794 }
694 795
695 /* Algorithm Negotiation */ 796 /* Algorithm Negotiation */
797 if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
798 sprop[PROPOSAL_KEX_ALGS])) != 0) {
799 kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
800 peer[PROPOSAL_KEX_ALGS] = NULL;
801 goto out;
802 }
803 if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
804 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
805 kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
806 peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
807 goto out;
808 }
696 for (mode = 0; mode < MODE_MAX; mode++) { 809 for (mode = 0; mode < MODE_MAX; mode++) {
697 if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { 810 if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) {
698 r = SSH_ERR_ALLOC_FAIL; 811 r = SSH_ERR_ALLOC_FAIL;
@@ -725,24 +838,12 @@ kex_choose_conf(struct ssh *ssh)
725 peer[ncomp] = NULL; 838 peer[ncomp] = NULL;
726 goto out; 839 goto out;
727 } 840 }
728 debug("kex: %s %s %s %s", 841 debug("kex: %s cipher: %s MAC: %s compression: %s",
729 ctos ? "client->server" : "server->client", 842 ctos ? "client->server" : "server->client",
730 newkeys->enc.name, 843 newkeys->enc.name,
731 authlen == 0 ? newkeys->mac.name : "<implicit>", 844 authlen == 0 ? newkeys->mac.name : "<implicit>",
732 newkeys->comp.name); 845 newkeys->comp.name);
733 } 846 }
734 if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
735 sprop[PROPOSAL_KEX_ALGS])) != 0) {
736 kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
737 peer[PROPOSAL_KEX_ALGS] = NULL;
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 }
746 need = dh_need = 0; 847 need = dh_need = 0;
747 for (mode = 0; mode < MODE_MAX; mode++) { 848 for (mode = 0; mode < MODE_MAX; mode++) {
748 newkeys = kex->newkeys[mode]; 849 newkeys = kex->newkeys[mode];
@@ -828,8 +929,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
828 digest = NULL; 929 digest = NULL;
829 r = 0; 930 r = 0;
830 out: 931 out:
831 if (digest) 932 free(digest);
832 free(digest);
833 ssh_digest_free(hashctx); 933 ssh_digest_free(hashctx);
834 return r; 934 return r;
835} 935}