diff options
-rw-r--r-- | kex.c | 80 |
1 files changed, 60 insertions, 20 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.c,v 1.151 2019/09/05 09:25:13 djm Exp $ */ | 1 | /* $OpenBSD: kex.c,v 1.152 2019/09/05 09:35:19 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 | * |
@@ -345,18 +345,25 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) | |||
345 | r = SSH_ERR_ALLOC_FAIL; | 345 | r = SSH_ERR_ALLOC_FAIL; |
346 | goto out; | 346 | goto out; |
347 | } | 347 | } |
348 | if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ | 348 | if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) { /* skip cookie */ |
349 | error("%s: consume cookie: %s", __func__, ssh_err(r)); | ||
349 | goto out; | 350 | goto out; |
351 | } | ||
350 | /* extract kex init proposal strings */ | 352 | /* extract kex init proposal strings */ |
351 | for (i = 0; i < PROPOSAL_MAX; i++) { | 353 | for (i = 0; i < PROPOSAL_MAX; i++) { |
352 | if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) | 354 | if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) { |
355 | error("%s: parse proposal %u: %s", __func__, | ||
356 | i, ssh_err(r)); | ||
353 | goto out; | 357 | goto out; |
358 | } | ||
354 | debug2("%s: %s", proposal_names[i], proposal[i]); | 359 | debug2("%s: %s", proposal_names[i], proposal[i]); |
355 | } | 360 | } |
356 | /* first kex follows / reserved */ | 361 | /* first kex follows / reserved */ |
357 | if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ | 362 | if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ |
358 | (r = sshbuf_get_u32(b, &i)) != 0) /* reserved */ | 363 | (r = sshbuf_get_u32(b, &i)) != 0) { /* reserved */ |
364 | error("%s: parse: %s", __func__, ssh_err(r)); | ||
359 | goto out; | 365 | goto out; |
366 | } | ||
360 | if (first_kex_follows != NULL) | 367 | if (first_kex_follows != NULL) |
361 | *first_kex_follows = v; | 368 | *first_kex_follows = v; |
362 | debug2("first_kex_follows %d ", v); | 369 | debug2("first_kex_follows %d ", v); |
@@ -417,8 +424,10 @@ kex_send_ext_info(struct ssh *ssh) | |||
417 | (r = sshpkt_put_u32(ssh, 1)) != 0 || | 424 | (r = sshpkt_put_u32(ssh, 1)) != 0 || |
418 | (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || | 425 | (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || |
419 | (r = sshpkt_put_cstring(ssh, algs)) != 0 || | 426 | (r = sshpkt_put_cstring(ssh, algs)) != 0 || |
420 | (r = sshpkt_send(ssh)) != 0) | 427 | (r = sshpkt_send(ssh)) != 0) { |
428 | error("%s: compose: %s", __func__, ssh_err(r)); | ||
421 | goto out; | 429 | goto out; |
430 | } | ||
422 | /* success */ | 431 | /* success */ |
423 | r = 0; | 432 | r = 0; |
424 | out: | 433 | out: |
@@ -512,23 +521,32 @@ kex_send_kexinit(struct ssh *ssh) | |||
512 | struct kex *kex = ssh->kex; | 521 | struct kex *kex = ssh->kex; |
513 | int r; | 522 | int r; |
514 | 523 | ||
515 | if (kex == NULL) | 524 | if (kex == NULL) { |
525 | error("%s: no hex", __func__); | ||
516 | return SSH_ERR_INTERNAL_ERROR; | 526 | return SSH_ERR_INTERNAL_ERROR; |
527 | } | ||
517 | if (kex->flags & KEX_INIT_SENT) | 528 | if (kex->flags & KEX_INIT_SENT) |
518 | return 0; | 529 | return 0; |
519 | kex->done = 0; | 530 | kex->done = 0; |
520 | 531 | ||
521 | /* generate a random cookie */ | 532 | /* generate a random cookie */ |
522 | if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) | 533 | if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) { |
534 | error("%s: bad kex length: %zu < %d", __func__, | ||
535 | sshbuf_len(kex->my), KEX_COOKIE_LEN); | ||
523 | return SSH_ERR_INVALID_FORMAT; | 536 | return SSH_ERR_INVALID_FORMAT; |
524 | if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) | 537 | } |
538 | if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) { | ||
539 | error("%s: buffer error", __func__); | ||
525 | return SSH_ERR_INTERNAL_ERROR; | 540 | return SSH_ERR_INTERNAL_ERROR; |
541 | } | ||
526 | arc4random_buf(cookie, KEX_COOKIE_LEN); | 542 | arc4random_buf(cookie, KEX_COOKIE_LEN); |
527 | 543 | ||
528 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || | 544 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || |
529 | (r = sshpkt_putb(ssh, kex->my)) != 0 || | 545 | (r = sshpkt_putb(ssh, kex->my)) != 0 || |
530 | (r = sshpkt_send(ssh)) != 0) | 546 | (r = sshpkt_send(ssh)) != 0) { |
547 | error("%s: compose reply: %s", __func__, ssh_err(r)); | ||
531 | return r; | 548 | return r; |
549 | } | ||
532 | debug("SSH2_MSG_KEXINIT sent"); | 550 | debug("SSH2_MSG_KEXINIT sent"); |
533 | kex->flags |= KEX_INIT_SENT; | 551 | kex->flags |= KEX_INIT_SENT; |
534 | return 0; | 552 | return 0; |
@@ -545,21 +563,28 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) | |||
545 | int r; | 563 | int r; |
546 | 564 | ||
547 | debug("SSH2_MSG_KEXINIT received"); | 565 | debug("SSH2_MSG_KEXINIT received"); |
548 | if (kex == NULL) | 566 | if (kex == NULL) { |
549 | return SSH_ERR_INVALID_ARGUMENT; | 567 | error("%s: no hex", __func__); |
550 | 568 | return SSH_ERR_INTERNAL_ERROR; | |
569 | } | ||
551 | ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); | 570 | ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); |
552 | ptr = sshpkt_ptr(ssh, &dlen); | 571 | ptr = sshpkt_ptr(ssh, &dlen); |
553 | if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) | 572 | if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) |
554 | return r; | 573 | return r; |
555 | 574 | ||
556 | /* discard packet */ | 575 | /* discard packet */ |
557 | for (i = 0; i < KEX_COOKIE_LEN; i++) | 576 | for (i = 0; i < KEX_COOKIE_LEN; i++) { |
558 | if ((r = sshpkt_get_u8(ssh, NULL)) != 0) | 577 | if ((r = sshpkt_get_u8(ssh, NULL)) != 0) { |
578 | error("%s: discard cookie: %s", __func__, ssh_err(r)); | ||
559 | return r; | 579 | return r; |
560 | for (i = 0; i < PROPOSAL_MAX; i++) | 580 | } |
561 | if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) | 581 | } |
582 | for (i = 0; i < PROPOSAL_MAX; i++) { | ||
583 | if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) { | ||
584 | error("%s: discard proposal: %s", __func__, ssh_err(r)); | ||
562 | return r; | 585 | return r; |
586 | } | ||
587 | } | ||
563 | /* | 588 | /* |
564 | * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported | 589 | * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported |
565 | * KEX method has the server move first, but a server might be using | 590 | * KEX method has the server move first, but a server might be using |
@@ -584,6 +609,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) | |||
584 | if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) | 609 | if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) |
585 | return (kex->kex[kex->kex_type])(ssh); | 610 | return (kex->kex[kex->kex_type])(ssh); |
586 | 611 | ||
612 | error("%s: unknown kex type %u", __func__, kex->kex_type); | ||
587 | return SSH_ERR_INTERNAL_ERROR; | 613 | return SSH_ERR_INTERNAL_ERROR; |
588 | } | 614 | } |
589 | 615 | ||
@@ -719,6 +745,7 @@ choose_enc(struct sshenc *enc, char *client, char *server) | |||
719 | if (name == NULL) | 745 | if (name == NULL) |
720 | return SSH_ERR_NO_CIPHER_ALG_MATCH; | 746 | return SSH_ERR_NO_CIPHER_ALG_MATCH; |
721 | if ((enc->cipher = cipher_by_name(name)) == NULL) { | 747 | if ((enc->cipher = cipher_by_name(name)) == NULL) { |
748 | error("%s: unsupported cipher %s", __func__, name); | ||
722 | free(name); | 749 | free(name); |
723 | return SSH_ERR_INTERNAL_ERROR; | 750 | return SSH_ERR_INTERNAL_ERROR; |
724 | } | 751 | } |
@@ -740,6 +767,7 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) | |||
740 | if (name == NULL) | 767 | if (name == NULL) |
741 | return SSH_ERR_NO_MAC_ALG_MATCH; | 768 | return SSH_ERR_NO_MAC_ALG_MATCH; |
742 | if (mac_setup(mac, name) < 0) { | 769 | if (mac_setup(mac, name) < 0) { |
770 | error("%s: unsupported MAC %s", __func__, name); | ||
743 | free(name); | 771 | free(name); |
744 | return SSH_ERR_INTERNAL_ERROR; | 772 | return SSH_ERR_INTERNAL_ERROR; |
745 | } | 773 | } |
@@ -763,6 +791,7 @@ choose_comp(struct sshcomp *comp, char *client, char *server) | |||
763 | } else if (strcmp(name, "none") == 0) { | 791 | } else if (strcmp(name, "none") == 0) { |
764 | comp->type = COMP_NONE; | 792 | comp->type = COMP_NONE; |
765 | } else { | 793 | } else { |
794 | error("%s: unsupported compression scheme %s", __func__, name); | ||
766 | free(name); | 795 | free(name); |
767 | return SSH_ERR_INTERNAL_ERROR; | 796 | return SSH_ERR_INTERNAL_ERROR; |
768 | } | 797 | } |
@@ -780,8 +809,10 @@ choose_kex(struct kex *k, char *client, char *server) | |||
780 | debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); | 809 | debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); |
781 | if (k->name == NULL) | 810 | if (k->name == NULL) |
782 | return SSH_ERR_NO_KEX_ALG_MATCH; | 811 | return SSH_ERR_NO_KEX_ALG_MATCH; |
783 | if ((kexalg = kex_alg_by_name(k->name)) == NULL) | 812 | if ((kexalg = kex_alg_by_name(k->name)) == NULL) { |
813 | error("%s: unsupported KEX method %s", __func__, k->name); | ||
784 | return SSH_ERR_INTERNAL_ERROR; | 814 | return SSH_ERR_INTERNAL_ERROR; |
815 | } | ||
785 | k->kex_type = kexalg->type; | 816 | k->kex_type = kexalg->type; |
786 | k->hash_alg = kexalg->hash_alg; | 817 | k->hash_alg = kexalg->hash_alg; |
787 | k->ec_nid = kexalg->ec_nid; | 818 | k->ec_nid = kexalg->ec_nid; |
@@ -798,8 +829,11 @@ choose_hostkeyalg(struct kex *k, char *client, char *server) | |||
798 | if (k->hostkey_alg == NULL) | 829 | if (k->hostkey_alg == NULL) |
799 | return SSH_ERR_NO_HOSTKEY_ALG_MATCH; | 830 | return SSH_ERR_NO_HOSTKEY_ALG_MATCH; |
800 | k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); | 831 | k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); |
801 | if (k->hostkey_type == KEY_UNSPEC) | 832 | if (k->hostkey_type == KEY_UNSPEC) { |
833 | error("%s: unsupported hostkey algorithm %s", __func__, | ||
834 | k->hostkey_alg); | ||
802 | return SSH_ERR_INTERNAL_ERROR; | 835 | return SSH_ERR_INTERNAL_ERROR; |
836 | } | ||
803 | k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); | 837 | k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); |
804 | return 0; | 838 | return 0; |
805 | } | 839 | } |
@@ -968,6 +1002,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, | |||
968 | kex->session_id_len) != 0 || | 1002 | kex->session_id_len) != 0 || |
969 | ssh_digest_final(hashctx, digest, mdsz) != 0) { | 1003 | ssh_digest_final(hashctx, digest, mdsz) != 0) { |
970 | r = SSH_ERR_LIBCRYPTO_ERROR; | 1004 | r = SSH_ERR_LIBCRYPTO_ERROR; |
1005 | error("%s: KEX hash failed", __func__); | ||
971 | goto out; | 1006 | goto out; |
972 | } | 1007 | } |
973 | ssh_digest_free(hashctx); | 1008 | ssh_digest_free(hashctx); |
@@ -984,6 +1019,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, | |||
984 | ssh_digest_update(hashctx, hash, hashlen) != 0 || | 1019 | ssh_digest_update(hashctx, hash, hashlen) != 0 || |
985 | ssh_digest_update(hashctx, digest, have) != 0 || | 1020 | ssh_digest_update(hashctx, digest, have) != 0 || |
986 | ssh_digest_final(hashctx, digest + have, mdsz) != 0) { | 1021 | ssh_digest_final(hashctx, digest + have, mdsz) != 0) { |
1022 | error("%s: KDF failed", __func__); | ||
987 | r = SSH_ERR_LIBCRYPTO_ERROR; | 1023 | r = SSH_ERR_LIBCRYPTO_ERROR; |
988 | goto out; | 1024 | goto out; |
989 | } | 1025 | } |
@@ -1047,8 +1083,10 @@ kex_load_hostkey(struct ssh *ssh, struct sshkey **prvp, struct sshkey **pubp) | |||
1047 | *pubp = NULL; | 1083 | *pubp = NULL; |
1048 | *prvp = NULL; | 1084 | *prvp = NULL; |
1049 | if (kex->load_host_public_key == NULL || | 1085 | if (kex->load_host_public_key == NULL || |
1050 | kex->load_host_private_key == NULL) | 1086 | kex->load_host_private_key == NULL) { |
1087 | error("%s: missing hostkey loader", __func__); | ||
1051 | return SSH_ERR_INVALID_ARGUMENT; | 1088 | return SSH_ERR_INVALID_ARGUMENT; |
1089 | } | ||
1052 | *pubp = kex->load_host_public_key(kex->hostkey_type, | 1090 | *pubp = kex->load_host_public_key(kex->hostkey_type, |
1053 | kex->hostkey_nid, ssh); | 1091 | kex->hostkey_nid, ssh); |
1054 | *prvp = kex->load_host_private_key(kex->hostkey_type, | 1092 | *prvp = kex->load_host_private_key(kex->hostkey_type, |
@@ -1063,8 +1101,10 @@ kex_verify_host_key(struct ssh *ssh, struct sshkey *server_host_key) | |||
1063 | { | 1101 | { |
1064 | struct kex *kex = ssh->kex; | 1102 | struct kex *kex = ssh->kex; |
1065 | 1103 | ||
1066 | if (kex->verify_host_key == NULL) | 1104 | if (kex->verify_host_key == NULL) { |
1105 | error("%s: missing hostkey verifier", __func__); | ||
1067 | return SSH_ERR_INVALID_ARGUMENT; | 1106 | return SSH_ERR_INVALID_ARGUMENT; |
1107 | } | ||
1068 | if (server_host_key->type != kex->hostkey_type || | 1108 | if (server_host_key->type != kex->hostkey_type || |
1069 | (kex->hostkey_type == KEY_ECDSA && | 1109 | (kex->hostkey_type == KEY_ECDSA && |
1070 | server_host_key->ecdsa_nid != kex->hostkey_nid)) | 1110 | server_host_key->ecdsa_nid != kex->hostkey_nid)) |