diff options
author | Colin Watson <cjwatson@debian.org> | 2019-06-05 06:41:44 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2019-06-05 06:41:44 +0100 |
commit | 102062f825fb26a74295a1c089c00c4c4c76b68a (patch) | |
tree | 3db66bc8c8483cce66516dff36f6ef56065143d9 /kex.c | |
parent | 3d246f10429fc9a37b98eabef94fe8dc7c61002b (diff) | |
parent | fd0fa130ecf06d7d092932adcd5d77f1549bfc8d (diff) |
Import openssh_8.0p1.orig.tar.gz
Diffstat (limited to 'kex.c')
-rw-r--r-- | kex.c | 350 |
1 files changed, 310 insertions, 40 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.c,v 1.141 2018/07/09 13:37:10 sf Exp $ */ | 1 | /* $OpenBSD: kex.c,v 1.150 2019/01/21 12:08:13 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 | * |
@@ -25,19 +25,25 @@ | |||
25 | 25 | ||
26 | #include "includes.h" | 26 | #include "includes.h" |
27 | 27 | ||
28 | 28 | #include <sys/types.h> | |
29 | #include <errno.h> | ||
29 | #include <signal.h> | 30 | #include <signal.h> |
30 | #include <stdarg.h> | 31 | #include <stdarg.h> |
31 | #include <stdio.h> | 32 | #include <stdio.h> |
32 | #include <stdlib.h> | 33 | #include <stdlib.h> |
33 | #include <string.h> | 34 | #include <string.h> |
35 | #include <unistd.h> | ||
36 | #include <poll.h> | ||
34 | 37 | ||
35 | #ifdef WITH_OPENSSL | 38 | #ifdef WITH_OPENSSL |
36 | #include <openssl/crypto.h> | 39 | #include <openssl/crypto.h> |
37 | #include <openssl/dh.h> | 40 | #include <openssl/dh.h> |
38 | #endif | 41 | #endif |
39 | 42 | ||
43 | #include "ssh.h" | ||
40 | #include "ssh2.h" | 44 | #include "ssh2.h" |
45 | #include "atomicio.h" | ||
46 | #include "version.h" | ||
41 | #include "packet.h" | 47 | #include "packet.h" |
42 | #include "compat.h" | 48 | #include "compat.h" |
43 | #include "cipher.h" | 49 | #include "cipher.h" |
@@ -102,6 +108,8 @@ static const struct kexalg kexalgs[] = { | |||
102 | #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) | 108 | #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) |
103 | { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, | 109 | { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, |
104 | { KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, | 110 | { KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, |
111 | { KEX_SNTRUP4591761X25519_SHA512, KEX_KEM_SNTRUP4591761X25519_SHA512, 0, | ||
112 | SSH_DIGEST_SHA512 }, | ||
105 | #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ | 113 | #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ |
106 | { NULL, -1, -1, -1}, | 114 | { NULL, -1, -1, -1}, |
107 | }; | 115 | }; |
@@ -487,6 +495,7 @@ kex_input_newkeys(int type, u_int32_t seq, struct ssh *ssh) | |||
487 | if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0) | 495 | if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0) |
488 | return r; | 496 | return r; |
489 | kex->done = 1; | 497 | kex->done = 1; |
498 | kex->flags &= ~KEX_INITIAL; | ||
490 | sshbuf_reset(kex->peer); | 499 | sshbuf_reset(kex->peer); |
491 | /* sshbuf_reset(kex->my); */ | 500 | /* sshbuf_reset(kex->my); */ |
492 | kex->flags &= ~KEX_INIT_SENT; | 501 | kex->flags &= ~KEX_INIT_SENT; |
@@ -577,31 +586,20 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) | |||
577 | return SSH_ERR_INTERNAL_ERROR; | 586 | return SSH_ERR_INTERNAL_ERROR; |
578 | } | 587 | } |
579 | 588 | ||
580 | int | 589 | struct kex * |
581 | kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) | 590 | kex_new(void) |
582 | { | 591 | { |
583 | struct kex *kex; | 592 | struct kex *kex; |
584 | int r; | ||
585 | 593 | ||
586 | *kexp = NULL; | 594 | if ((kex = calloc(1, sizeof(*kex))) == NULL || |
587 | if ((kex = calloc(1, sizeof(*kex))) == NULL) | 595 | (kex->peer = sshbuf_new()) == NULL || |
588 | return SSH_ERR_ALLOC_FAIL; | 596 | (kex->my = sshbuf_new()) == NULL || |
589 | if ((kex->peer = sshbuf_new()) == NULL || | 597 | (kex->client_version = sshbuf_new()) == NULL || |
590 | (kex->my = sshbuf_new()) == NULL) { | 598 | (kex->server_version = sshbuf_new()) == NULL) { |
591 | r = SSH_ERR_ALLOC_FAIL; | ||
592 | goto out; | ||
593 | } | ||
594 | if ((r = kex_prop2buf(kex->my, proposal)) != 0) | ||
595 | goto out; | ||
596 | kex->done = 0; | ||
597 | kex_reset_dispatch(ssh); | ||
598 | ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); | ||
599 | r = 0; | ||
600 | *kexp = kex; | ||
601 | out: | ||
602 | if (r != 0) | ||
603 | kex_free(kex); | 599 | kex_free(kex); |
604 | return r; | 600 | return NULL; |
601 | } | ||
602 | return kex; | ||
605 | } | 603 | } |
606 | 604 | ||
607 | void | 605 | void |
@@ -640,6 +638,9 @@ kex_free(struct kex *kex) | |||
640 | { | 638 | { |
641 | u_int mode; | 639 | u_int mode; |
642 | 640 | ||
641 | if (kex == NULL) | ||
642 | return; | ||
643 | |||
643 | #ifdef WITH_OPENSSL | 644 | #ifdef WITH_OPENSSL |
644 | DH_free(kex->dh); | 645 | DH_free(kex->dh); |
645 | #ifdef OPENSSL_HAS_ECC | 646 | #ifdef OPENSSL_HAS_ECC |
@@ -652,9 +653,10 @@ kex_free(struct kex *kex) | |||
652 | } | 653 | } |
653 | sshbuf_free(kex->peer); | 654 | sshbuf_free(kex->peer); |
654 | sshbuf_free(kex->my); | 655 | sshbuf_free(kex->my); |
656 | sshbuf_free(kex->client_version); | ||
657 | sshbuf_free(kex->server_version); | ||
658 | sshbuf_free(kex->client_pub); | ||
655 | free(kex->session_id); | 659 | free(kex->session_id); |
656 | free(kex->client_version_string); | ||
657 | free(kex->server_version_string); | ||
658 | free(kex->failed_choice); | 660 | free(kex->failed_choice); |
659 | free(kex->hostkey_alg); | 661 | free(kex->hostkey_alg); |
660 | free(kex->name); | 662 | free(kex->name); |
@@ -662,11 +664,24 @@ kex_free(struct kex *kex) | |||
662 | } | 664 | } |
663 | 665 | ||
664 | int | 666 | int |
667 | kex_ready(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) | ||
668 | { | ||
669 | int r; | ||
670 | |||
671 | if ((r = kex_prop2buf(ssh->kex->my, proposal)) != 0) | ||
672 | return r; | ||
673 | ssh->kex->flags = KEX_INITIAL; | ||
674 | kex_reset_dispatch(ssh); | ||
675 | ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | int | ||
665 | kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) | 680 | kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) |
666 | { | 681 | { |
667 | int r; | 682 | int r; |
668 | 683 | ||
669 | if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) | 684 | if ((r = kex_ready(ssh, proposal)) != 0) |
670 | return r; | 685 | return r; |
671 | if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ | 686 | if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ |
672 | kex_free(ssh->kex); | 687 | kex_free(ssh->kex); |
@@ -839,7 +854,7 @@ kex_choose_conf(struct ssh *ssh) | |||
839 | } | 854 | } |
840 | 855 | ||
841 | /* Check whether client supports ext_info_c */ | 856 | /* Check whether client supports ext_info_c */ |
842 | if (kex->server) { | 857 | if (kex->server && (kex->flags & KEX_INITIAL)) { |
843 | char *ext; | 858 | char *ext; |
844 | 859 | ||
845 | ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); | 860 | ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); |
@@ -997,6 +1012,14 @@ kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, | |||
997 | u_int i, j, mode, ctos; | 1012 | u_int i, j, mode, ctos; |
998 | int r; | 1013 | int r; |
999 | 1014 | ||
1015 | /* save initial hash as session id */ | ||
1016 | if (kex->session_id == NULL) { | ||
1017 | kex->session_id_len = hashlen; | ||
1018 | kex->session_id = malloc(kex->session_id_len); | ||
1019 | if (kex->session_id == NULL) | ||
1020 | return SSH_ERR_ALLOC_FAIL; | ||
1021 | memcpy(kex->session_id, hash, kex->session_id_len); | ||
1022 | } | ||
1000 | for (i = 0; i < NKEYS; i++) { | 1023 | for (i = 0; i < NKEYS; i++) { |
1001 | if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, | 1024 | if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, |
1002 | shared_secret, &keys[i])) != 0) { | 1025 | shared_secret, &keys[i])) != 0) { |
@@ -1015,29 +1038,276 @@ kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, | |||
1015 | return 0; | 1038 | return 0; |
1016 | } | 1039 | } |
1017 | 1040 | ||
1018 | #ifdef WITH_OPENSSL | ||
1019 | int | 1041 | int |
1020 | kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, | 1042 | kex_load_hostkey(struct ssh *ssh, struct sshkey **prvp, struct sshkey **pubp) |
1021 | const BIGNUM *secret) | ||
1022 | { | 1043 | { |
1023 | struct sshbuf *shared_secret; | 1044 | struct kex *kex = ssh->kex; |
1024 | int r; | ||
1025 | 1045 | ||
1026 | if ((shared_secret = sshbuf_new()) == NULL) | 1046 | *pubp = NULL; |
1027 | return SSH_ERR_ALLOC_FAIL; | 1047 | *prvp = NULL; |
1028 | if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) | 1048 | if (kex->load_host_public_key == NULL || |
1029 | r = kex_derive_keys(ssh, hash, hashlen, shared_secret); | 1049 | kex->load_host_private_key == NULL) |
1030 | sshbuf_free(shared_secret); | 1050 | return SSH_ERR_INVALID_ARGUMENT; |
1031 | return r; | 1051 | *pubp = kex->load_host_public_key(kex->hostkey_type, |
1052 | kex->hostkey_nid, ssh); | ||
1053 | *prvp = kex->load_host_private_key(kex->hostkey_type, | ||
1054 | kex->hostkey_nid, ssh); | ||
1055 | if (*pubp == NULL) | ||
1056 | return SSH_ERR_NO_HOSTKEY_LOADED; | ||
1057 | return 0; | ||
1032 | } | 1058 | } |
1033 | #endif | ||
1034 | 1059 | ||
1060 | int | ||
1061 | kex_verify_host_key(struct ssh *ssh, struct sshkey *server_host_key) | ||
1062 | { | ||
1063 | struct kex *kex = ssh->kex; | ||
1064 | |||
1065 | if (kex->verify_host_key == NULL) | ||
1066 | return SSH_ERR_INVALID_ARGUMENT; | ||
1067 | if (server_host_key->type != kex->hostkey_type || | ||
1068 | (kex->hostkey_type == KEY_ECDSA && | ||
1069 | server_host_key->ecdsa_nid != kex->hostkey_nid)) | ||
1070 | return SSH_ERR_KEY_TYPE_MISMATCH; | ||
1071 | if (kex->verify_host_key(server_host_key, ssh) == -1) | ||
1072 | return SSH_ERR_SIGNATURE_INVALID; | ||
1073 | return 0; | ||
1074 | } | ||
1035 | 1075 | ||
1036 | #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) | 1076 | #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) |
1037 | void | 1077 | void |
1038 | dump_digest(char *msg, u_char *digest, int len) | 1078 | dump_digest(const char *msg, const u_char *digest, int len) |
1039 | { | 1079 | { |
1040 | fprintf(stderr, "%s\n", msg); | 1080 | fprintf(stderr, "%s\n", msg); |
1041 | sshbuf_dump_data(digest, len, stderr); | 1081 | sshbuf_dump_data(digest, len, stderr); |
1042 | } | 1082 | } |
1043 | #endif | 1083 | #endif |
1084 | |||
1085 | /* | ||
1086 | * Send a plaintext error message to the peer, suffixed by \r\n. | ||
1087 | * Only used during banner exchange, and there only for the server. | ||
1088 | */ | ||
1089 | static void | ||
1090 | send_error(struct ssh *ssh, char *msg) | ||
1091 | { | ||
1092 | char *crnl = "\r\n"; | ||
1093 | |||
1094 | if (!ssh->kex->server) | ||
1095 | return; | ||
1096 | |||
1097 | if (atomicio(vwrite, ssh_packet_get_connection_out(ssh), | ||
1098 | msg, strlen(msg)) != strlen(msg) || | ||
1099 | atomicio(vwrite, ssh_packet_get_connection_out(ssh), | ||
1100 | crnl, strlen(crnl)) != strlen(crnl)) | ||
1101 | error("%s: write: %.100s", __func__, strerror(errno)); | ||
1102 | } | ||
1103 | |||
1104 | /* | ||
1105 | * Sends our identification string and waits for the peer's. Will block for | ||
1106 | * up to timeout_ms (or indefinitely if timeout_ms <= 0). | ||
1107 | * Returns on 0 success or a ssherr.h code on failure. | ||
1108 | */ | ||
1109 | int | ||
1110 | kex_exchange_identification(struct ssh *ssh, int timeout_ms, | ||
1111 | const char *version_addendum) | ||
1112 | { | ||
1113 | int remote_major, remote_minor, mismatch; | ||
1114 | size_t len, i, n; | ||
1115 | int r, expect_nl; | ||
1116 | u_char c; | ||
1117 | struct sshbuf *our_version = ssh->kex->server ? | ||
1118 | ssh->kex->server_version : ssh->kex->client_version; | ||
1119 | struct sshbuf *peer_version = ssh->kex->server ? | ||
1120 | ssh->kex->client_version : ssh->kex->server_version; | ||
1121 | char *our_version_string = NULL, *peer_version_string = NULL; | ||
1122 | char *cp, *remote_version = NULL; | ||
1123 | |||
1124 | /* Prepare and send our banner */ | ||
1125 | sshbuf_reset(our_version); | ||
1126 | if (version_addendum != NULL && *version_addendum == '\0') | ||
1127 | version_addendum = NULL; | ||
1128 | if ((r = sshbuf_putf(our_version, "SSH-%d.%d-%.100s%s%s\r\n", | ||
1129 | PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION, | ||
1130 | version_addendum == NULL ? "" : " ", | ||
1131 | version_addendum == NULL ? "" : version_addendum)) != 0) { | ||
1132 | error("%s: sshbuf_putf: %s", __func__, ssh_err(r)); | ||
1133 | goto out; | ||
1134 | } | ||
1135 | |||
1136 | if (atomicio(vwrite, ssh_packet_get_connection_out(ssh), | ||
1137 | sshbuf_mutable_ptr(our_version), | ||
1138 | sshbuf_len(our_version)) != sshbuf_len(our_version)) { | ||
1139 | error("%s: write: %.100s", __func__, strerror(errno)); | ||
1140 | r = SSH_ERR_SYSTEM_ERROR; | ||
1141 | goto out; | ||
1142 | } | ||
1143 | if ((r = sshbuf_consume_end(our_version, 2)) != 0) { /* trim \r\n */ | ||
1144 | error("%s: sshbuf_consume_end: %s", __func__, ssh_err(r)); | ||
1145 | goto out; | ||
1146 | } | ||
1147 | our_version_string = sshbuf_dup_string(our_version); | ||
1148 | if (our_version_string == NULL) { | ||
1149 | error("%s: sshbuf_dup_string failed", __func__); | ||
1150 | r = SSH_ERR_ALLOC_FAIL; | ||
1151 | goto out; | ||
1152 | } | ||
1153 | debug("Local version string %.100s", our_version_string); | ||
1154 | |||
1155 | /* Read other side's version identification. */ | ||
1156 | for (n = 0; ; n++) { | ||
1157 | if (n >= SSH_MAX_PRE_BANNER_LINES) { | ||
1158 | send_error(ssh, "No SSH identification string " | ||
1159 | "received."); | ||
1160 | error("%s: No SSH version received in first %u lines " | ||
1161 | "from server", __func__, SSH_MAX_PRE_BANNER_LINES); | ||
1162 | r = SSH_ERR_INVALID_FORMAT; | ||
1163 | goto out; | ||
1164 | } | ||
1165 | sshbuf_reset(peer_version); | ||
1166 | expect_nl = 0; | ||
1167 | for (i = 0; ; i++) { | ||
1168 | if (timeout_ms > 0) { | ||
1169 | r = waitrfd(ssh_packet_get_connection_in(ssh), | ||
1170 | &timeout_ms); | ||
1171 | if (r == -1 && errno == ETIMEDOUT) { | ||
1172 | send_error(ssh, "Timed out waiting " | ||
1173 | "for SSH identification string."); | ||
1174 | error("Connection timed out during " | ||
1175 | "banner exchange"); | ||
1176 | r = SSH_ERR_CONN_TIMEOUT; | ||
1177 | goto out; | ||
1178 | } else if (r == -1) { | ||
1179 | error("%s: %s", | ||
1180 | __func__, strerror(errno)); | ||
1181 | r = SSH_ERR_SYSTEM_ERROR; | ||
1182 | goto out; | ||
1183 | } | ||
1184 | } | ||
1185 | |||
1186 | len = atomicio(read, ssh_packet_get_connection_in(ssh), | ||
1187 | &c, 1); | ||
1188 | if (len != 1 && errno == EPIPE) { | ||
1189 | error("%s: Connection closed by remote host", | ||
1190 | __func__); | ||
1191 | r = SSH_ERR_CONN_CLOSED; | ||
1192 | goto out; | ||
1193 | } else if (len != 1) { | ||
1194 | error("%s: read: %.100s", | ||
1195 | __func__, strerror(errno)); | ||
1196 | r = SSH_ERR_SYSTEM_ERROR; | ||
1197 | goto out; | ||
1198 | } | ||
1199 | if (c == '\r') { | ||
1200 | expect_nl = 1; | ||
1201 | continue; | ||
1202 | } | ||
1203 | if (c == '\n') | ||
1204 | break; | ||
1205 | if (c == '\0' || expect_nl) { | ||
1206 | error("%s: banner line contains invalid " | ||
1207 | "characters", __func__); | ||
1208 | goto invalid; | ||
1209 | } | ||
1210 | if ((r = sshbuf_put_u8(peer_version, c)) != 0) { | ||
1211 | error("%s: sshbuf_put: %s", | ||
1212 | __func__, ssh_err(r)); | ||
1213 | goto out; | ||
1214 | } | ||
1215 | if (sshbuf_len(peer_version) > SSH_MAX_BANNER_LEN) { | ||
1216 | error("%s: banner line too long", __func__); | ||
1217 | goto invalid; | ||
1218 | } | ||
1219 | } | ||
1220 | /* Is this an actual protocol banner? */ | ||
1221 | if (sshbuf_len(peer_version) > 4 && | ||
1222 | memcmp(sshbuf_ptr(peer_version), "SSH-", 4) == 0) | ||
1223 | break; | ||
1224 | /* If not, then just log the line and continue */ | ||
1225 | if ((cp = sshbuf_dup_string(peer_version)) == NULL) { | ||
1226 | error("%s: sshbuf_dup_string failed", __func__); | ||
1227 | r = SSH_ERR_ALLOC_FAIL; | ||
1228 | goto out; | ||
1229 | } | ||
1230 | /* Do not accept lines before the SSH ident from a client */ | ||
1231 | if (ssh->kex->server) { | ||
1232 | error("%s: client sent invalid protocol identifier " | ||
1233 | "\"%.256s\"", __func__, cp); | ||
1234 | free(cp); | ||
1235 | goto invalid; | ||
1236 | } | ||
1237 | debug("%s: banner line %zu: %s", __func__, n, cp); | ||
1238 | free(cp); | ||
1239 | } | ||
1240 | peer_version_string = sshbuf_dup_string(peer_version); | ||
1241 | if (peer_version_string == NULL) | ||
1242 | error("%s: sshbuf_dup_string failed", __func__); | ||
1243 | /* XXX must be same size for sscanf */ | ||
1244 | if ((remote_version = calloc(1, sshbuf_len(peer_version))) == NULL) { | ||
1245 | error("%s: calloc failed", __func__); | ||
1246 | r = SSH_ERR_ALLOC_FAIL; | ||
1247 | goto out; | ||
1248 | } | ||
1249 | |||
1250 | /* | ||
1251 | * Check that the versions match. In future this might accept | ||
1252 | * several versions and set appropriate flags to handle them. | ||
1253 | */ | ||
1254 | if (sscanf(peer_version_string, "SSH-%d.%d-%[^\n]\n", | ||
1255 | &remote_major, &remote_minor, remote_version) != 3) { | ||
1256 | error("Bad remote protocol version identification: '%.100s'", | ||
1257 | peer_version_string); | ||
1258 | invalid: | ||
1259 | send_error(ssh, "Invalid SSH identification string."); | ||
1260 | r = SSH_ERR_INVALID_FORMAT; | ||
1261 | goto out; | ||
1262 | } | ||
1263 | debug("Remote protocol version %d.%d, remote software version %.100s", | ||
1264 | remote_major, remote_minor, remote_version); | ||
1265 | ssh->compat = compat_datafellows(remote_version); | ||
1266 | |||
1267 | mismatch = 0; | ||
1268 | switch (remote_major) { | ||
1269 | case 2: | ||
1270 | break; | ||
1271 | case 1: | ||
1272 | if (remote_minor != 99) | ||
1273 | mismatch = 1; | ||
1274 | break; | ||
1275 | default: | ||
1276 | mismatch = 1; | ||
1277 | break; | ||
1278 | } | ||
1279 | if (mismatch) { | ||
1280 | error("Protocol major versions differ: %d vs. %d", | ||
1281 | PROTOCOL_MAJOR_2, remote_major); | ||
1282 | send_error(ssh, "Protocol major versions differ."); | ||
1283 | r = SSH_ERR_NO_PROTOCOL_VERSION; | ||
1284 | goto out; | ||
1285 | } | ||
1286 | |||
1287 | if (ssh->kex->server && (ssh->compat & SSH_BUG_PROBE) != 0) { | ||
1288 | logit("probed from %s port %d with %s. Don't panic.", | ||
1289 | ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), | ||
1290 | peer_version_string); | ||
1291 | r = SSH_ERR_CONN_CLOSED; /* XXX */ | ||
1292 | goto out; | ||
1293 | } | ||
1294 | if (ssh->kex->server && (ssh->compat & SSH_BUG_SCANNER) != 0) { | ||
1295 | logit("scanned from %s port %d with %s. Don't panic.", | ||
1296 | ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), | ||
1297 | peer_version_string); | ||
1298 | r = SSH_ERR_CONN_CLOSED; /* XXX */ | ||
1299 | goto out; | ||
1300 | } | ||
1301 | if ((ssh->compat & SSH_BUG_RSASIGMD5) != 0) { | ||
1302 | logit("Remote version \"%.100s\" uses unsafe RSA signature " | ||
1303 | "scheme; disabling use of RSA keys", remote_version); | ||
1304 | } | ||
1305 | /* success */ | ||
1306 | r = 0; | ||
1307 | out: | ||
1308 | free(our_version_string); | ||
1309 | free(peer_version_string); | ||
1310 | free(remote_version); | ||
1311 | return r; | ||
1312 | } | ||
1313 | |||