diff options
author | Colin Watson <cjwatson@debian.org> | 2016-02-29 12:15:15 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2016-02-29 12:15:15 +0000 |
commit | c52a95cc4754e6630c96fe65ae0c65eb41d2c590 (patch) | |
tree | 793395934013923b7b2426382c0676edcd4be3d4 /kex.c | |
parent | eeff4de96f5d7365750dc56912c2c62b5c28db6b (diff) | |
parent | 72b061d4ba0f909501c595d709ea76e06b01e5c9 (diff) |
Import openssh_7.2p1.orig.tar.gz
Diffstat (limited to 'kex.c')
-rw-r--r-- | kex.c | 168 |
1 files changed, 134 insertions, 34 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.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" |
@@ -67,6 +66,19 @@ extern const EVP_MD *evp_ssh_sha256(void); | |||
67 | static int kex_choose_conf(struct ssh *); | 66 | static int kex_choose_conf(struct ssh *); |
68 | static int kex_input_newkeys(int, u_int32_t, void *); | 67 | static int kex_input_newkeys(int, u_int32_t, void *); |
69 | 68 | ||
69 | static const char *proposal_names[PROPOSAL_MAX] = { | ||
70 | "KEX algorithms", | ||
71 | "host key algorithms", | ||
72 | "ciphers ctos", | ||
73 | "ciphers stoc", | ||
74 | "MACs ctos", | ||
75 | "MACs stoc", | ||
76 | "compression ctos", | ||
77 | "compression stoc", | ||
78 | "languages ctos", | ||
79 | "languages stoc", | ||
80 | }; | ||
81 | |||
70 | struct kexalg { | 82 | struct kexalg { |
71 | char *name; | 83 | char *name; |
72 | u_int type; | 84 | u_int type; |
@@ -267,7 +279,7 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) | |||
267 | for (i = 0; i < PROPOSAL_MAX; i++) { | 279 | for (i = 0; i < PROPOSAL_MAX; i++) { |
268 | if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) | 280 | if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) |
269 | goto out; | 281 | goto out; |
270 | debug2("kex_parse_kexinit: %s", proposal[i]); | 282 | debug2("%s: %s", proposal_names[i], proposal[i]); |
271 | } | 283 | } |
272 | /* first kex follows / reserved */ | 284 | /* first kex follows / reserved */ |
273 | if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ | 285 | if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ |
@@ -302,7 +314,14 @@ kex_prop_free(char **proposal) | |||
302 | static int | 314 | static int |
303 | kex_protocol_error(int type, u_int32_t seq, void *ctxt) | 315 | kex_protocol_error(int type, u_int32_t seq, void *ctxt) |
304 | { | 316 | { |
305 | error("Hm, kex protocol error: type %d seq %u", type, seq); | 317 | struct ssh *ssh = active_state; /* XXX */ |
318 | int r; | ||
319 | |||
320 | error("kex protocol error: type %d seq %u", type, seq); | ||
321 | if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || | ||
322 | (r = sshpkt_put_u32(ssh, seq)) != 0 || | ||
323 | (r = sshpkt_send(ssh)) != 0) | ||
324 | return r; | ||
306 | return 0; | 325 | return 0; |
307 | } | 326 | } |
308 | 327 | ||
@@ -314,6 +333,20 @@ kex_reset_dispatch(struct ssh *ssh) | |||
314 | ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); | 333 | ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); |
315 | } | 334 | } |
316 | 335 | ||
336 | static int | ||
337 | kex_send_ext_info(struct ssh *ssh) | ||
338 | { | ||
339 | int r; | ||
340 | |||
341 | if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 || | ||
342 | (r = sshpkt_put_u32(ssh, 1)) != 0 || | ||
343 | (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || | ||
344 | (r = sshpkt_put_cstring(ssh, "rsa-sha2-256,rsa-sha2-512")) != 0 || | ||
345 | (r = sshpkt_send(ssh)) != 0) | ||
346 | return r; | ||
347 | return 0; | ||
348 | } | ||
349 | |||
317 | int | 350 | int |
318 | kex_send_newkeys(struct ssh *ssh) | 351 | kex_send_newkeys(struct ssh *ssh) |
319 | { | 352 | { |
@@ -326,9 +359,51 @@ kex_send_newkeys(struct ssh *ssh) | |||
326 | debug("SSH2_MSG_NEWKEYS sent"); | 359 | debug("SSH2_MSG_NEWKEYS sent"); |
327 | debug("expecting SSH2_MSG_NEWKEYS"); | 360 | debug("expecting SSH2_MSG_NEWKEYS"); |
328 | ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); | 361 | ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); |
362 | if (ssh->kex->ext_info_c) | ||
363 | if ((r = kex_send_ext_info(ssh)) != 0) | ||
364 | return r; | ||
329 | return 0; | 365 | return 0; |
330 | } | 366 | } |
331 | 367 | ||
368 | int | ||
369 | kex_input_ext_info(int type, u_int32_t seq, void *ctxt) | ||
370 | { | ||
371 | struct ssh *ssh = ctxt; | ||
372 | struct kex *kex = ssh->kex; | ||
373 | u_int32_t i, ninfo; | ||
374 | char *name, *val, *found; | ||
375 | int r; | ||
376 | |||
377 | debug("SSH2_MSG_EXT_INFO received"); | ||
378 | ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error); | ||
379 | if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0) | ||
380 | return r; | ||
381 | for (i = 0; i < ninfo; i++) { | ||
382 | if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0) | ||
383 | return r; | ||
384 | if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) { | ||
385 | free(name); | ||
386 | return r; | ||
387 | } | ||
388 | debug("%s: %s=<%s>", __func__, name, val); | ||
389 | if (strcmp(name, "server-sig-algs") == 0) { | ||
390 | found = match_list("rsa-sha2-256", val, NULL); | ||
391 | if (found) { | ||
392 | kex->rsa_sha2 = 256; | ||
393 | free(found); | ||
394 | } | ||
395 | found = match_list("rsa-sha2-512", val, NULL); | ||
396 | if (found) { | ||
397 | kex->rsa_sha2 = 512; | ||
398 | free(found); | ||
399 | } | ||
400 | } | ||
401 | free(name); | ||
402 | free(val); | ||
403 | } | ||
404 | return sshpkt_get_end(ssh); | ||
405 | } | ||
406 | |||
332 | static int | 407 | static int |
333 | kex_input_newkeys(int type, u_int32_t seq, void *ctxt) | 408 | kex_input_newkeys(int type, u_int32_t seq, void *ctxt) |
334 | { | 409 | { |
@@ -468,7 +543,7 @@ kex_free_newkeys(struct newkeys *newkeys) | |||
468 | newkeys->enc.key = NULL; | 543 | newkeys->enc.key = NULL; |
469 | } | 544 | } |
470 | if (newkeys->enc.iv) { | 545 | if (newkeys->enc.iv) { |
471 | explicit_bzero(newkeys->enc.iv, newkeys->enc.block_size); | 546 | explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len); |
472 | free(newkeys->enc.iv); | 547 | free(newkeys->enc.iv); |
473 | newkeys->enc.iv = NULL; | 548 | newkeys->enc.iv = NULL; |
474 | } | 549 | } |
@@ -511,6 +586,8 @@ kex_free(struct kex *kex) | |||
511 | free(kex->client_version_string); | 586 | free(kex->client_version_string); |
512 | free(kex->server_version_string); | 587 | free(kex->server_version_string); |
513 | free(kex->failed_choice); | 588 | free(kex->failed_choice); |
589 | free(kex->hostkey_alg); | ||
590 | free(kex->name); | ||
514 | free(kex); | 591 | free(kex); |
515 | } | 592 | } |
516 | 593 | ||
@@ -529,6 +606,25 @@ kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) | |||
529 | return 0; | 606 | return 0; |
530 | } | 607 | } |
531 | 608 | ||
609 | /* | ||
610 | * Request key re-exchange, returns 0 on success or a ssherr.h error | ||
611 | * code otherwise. Must not be called if KEX is incomplete or in-progress. | ||
612 | */ | ||
613 | int | ||
614 | kex_start_rekex(struct ssh *ssh) | ||
615 | { | ||
616 | if (ssh->kex == NULL) { | ||
617 | error("%s: no kex", __func__); | ||
618 | return SSH_ERR_INTERNAL_ERROR; | ||
619 | } | ||
620 | if (ssh->kex->done == 0) { | ||
621 | error("%s: requested twice", __func__); | ||
622 | return SSH_ERR_INTERNAL_ERROR; | ||
623 | } | ||
624 | ssh->kex->done = 0; | ||
625 | return kex_send_kexinit(ssh); | ||
626 | } | ||
627 | |||
532 | static int | 628 | static int |
533 | choose_enc(struct sshenc *enc, char *client, char *server) | 629 | choose_enc(struct sshenc *enc, char *client, char *server) |
534 | { | 630 | { |
@@ -593,6 +689,7 @@ choose_kex(struct kex *k, char *client, char *server) | |||
593 | 689 | ||
594 | k->name = match_list(client, server, NULL); | 690 | k->name = match_list(client, server, NULL); |
595 | 691 | ||
692 | debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); | ||
596 | if (k->name == NULL) | 693 | if (k->name == NULL) |
597 | return SSH_ERR_NO_KEX_ALG_MATCH; | 694 | return SSH_ERR_NO_KEX_ALG_MATCH; |
598 | if ((kexalg = kex_alg_by_name(k->name)) == NULL) | 695 | if ((kexalg = kex_alg_by_name(k->name)) == NULL) |
@@ -606,15 +703,16 @@ choose_kex(struct kex *k, char *client, char *server) | |||
606 | static int | 703 | static int |
607 | choose_hostkeyalg(struct kex *k, char *client, char *server) | 704 | choose_hostkeyalg(struct kex *k, char *client, char *server) |
608 | { | 705 | { |
609 | char *hostkeyalg = match_list(client, server, NULL); | 706 | k->hostkey_alg = match_list(client, server, NULL); |
610 | 707 | ||
611 | if (hostkeyalg == NULL) | 708 | debug("kex: host key algorithm: %s", |
709 | k->hostkey_alg ? k->hostkey_alg : "(no match)"); | ||
710 | if (k->hostkey_alg == NULL) | ||
612 | return SSH_ERR_NO_HOSTKEY_ALG_MATCH; | 711 | return SSH_ERR_NO_HOSTKEY_ALG_MATCH; |
613 | k->hostkey_type = sshkey_type_from_name(hostkeyalg); | 712 | k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); |
614 | if (k->hostkey_type == KEY_UNSPEC) | 713 | if (k->hostkey_type == KEY_UNSPEC) |
615 | return SSH_ERR_INTERNAL_ERROR; | 714 | return SSH_ERR_INTERNAL_ERROR; |
616 | k->hostkey_nid = sshkey_ecdsa_nid_from_name(hostkeyalg); | 715 | k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); |
617 | free(hostkeyalg); | ||
618 | return 0; | 716 | return 0; |
619 | } | 717 | } |
620 | 718 | ||
@@ -653,8 +751,11 @@ kex_choose_conf(struct ssh *ssh) | |||
653 | u_int mode, ctos, need, dh_need, authlen; | 751 | u_int mode, ctos, need, dh_need, authlen; |
654 | int r, first_kex_follows; | 752 | int r, first_kex_follows; |
655 | 753 | ||
656 | if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 || | 754 | debug2("local %s KEXINIT proposal", kex->server ? "server" : "client"); |
657 | (r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) | 755 | if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0) |
756 | goto out; | ||
757 | debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server"); | ||
758 | if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) | ||
658 | goto out; | 759 | goto out; |
659 | 760 | ||
660 | if (kex->server) { | 761 | if (kex->server) { |
@@ -665,18 +766,30 @@ kex_choose_conf(struct ssh *ssh) | |||
665 | sprop=peer; | 766 | sprop=peer; |
666 | } | 767 | } |
667 | 768 | ||
668 | /* Check whether server offers roaming */ | 769 | /* Check whether client supports ext_info_c */ |
669 | if (!kex->server) { | 770 | if (kex->server) { |
670 | char *roaming = match_list(KEX_RESUME, | 771 | char *ext; |
671 | peer[PROPOSAL_KEX_ALGS], NULL); | ||
672 | 772 | ||
673 | if (roaming) { | 773 | ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); |
674 | kex->roaming = 1; | 774 | if (ext) { |
675 | free(roaming); | 775 | kex->ext_info_c = 1; |
776 | free(ext); | ||
676 | } | 777 | } |
677 | } | 778 | } |
678 | 779 | ||
679 | /* Algorithm Negotiation */ | 780 | /* Algorithm Negotiation */ |
781 | if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], | ||
782 | sprop[PROPOSAL_KEX_ALGS])) != 0) { | ||
783 | kex->failed_choice = peer[PROPOSAL_KEX_ALGS]; | ||
784 | peer[PROPOSAL_KEX_ALGS] = NULL; | ||
785 | goto out; | ||
786 | } | ||
787 | if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
788 | sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) { | ||
789 | kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
790 | peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL; | ||
791 | goto out; | ||
792 | } | ||
680 | for (mode = 0; mode < MODE_MAX; mode++) { | 793 | for (mode = 0; mode < MODE_MAX; mode++) { |
681 | if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { | 794 | if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { |
682 | r = SSH_ERR_ALLOC_FAIL; | 795 | r = SSH_ERR_ALLOC_FAIL; |
@@ -709,24 +822,12 @@ kex_choose_conf(struct ssh *ssh) | |||
709 | peer[ncomp] = NULL; | 822 | peer[ncomp] = NULL; |
710 | goto out; | 823 | goto out; |
711 | } | 824 | } |
712 | debug("kex: %s %s %s %s", | 825 | debug("kex: %s cipher: %s MAC: %s compression: %s", |
713 | ctos ? "client->server" : "server->client", | 826 | ctos ? "client->server" : "server->client", |
714 | newkeys->enc.name, | 827 | newkeys->enc.name, |
715 | authlen == 0 ? newkeys->mac.name : "<implicit>", | 828 | authlen == 0 ? newkeys->mac.name : "<implicit>", |
716 | newkeys->comp.name); | 829 | newkeys->comp.name); |
717 | } | 830 | } |
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; | 831 | need = dh_need = 0; |
731 | for (mode = 0; mode < MODE_MAX; mode++) { | 832 | for (mode = 0; mode < MODE_MAX; mode++) { |
732 | newkeys = kex->newkeys[mode]; | 833 | newkeys = kex->newkeys[mode]; |
@@ -812,8 +913,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, | |||
812 | digest = NULL; | 913 | digest = NULL; |
813 | r = 0; | 914 | r = 0; |
814 | out: | 915 | out: |
815 | if (digest) | 916 | free(digest); |
816 | free(digest); | ||
817 | ssh_digest_free(hashctx); | 917 | ssh_digest_free(hashctx); |
818 | return r; | 918 | return r; |
819 | } | 919 | } |