summaryrefslogtreecommitdiff
path: root/kex.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2019-06-05 06:41:44 +0100
committerColin Watson <cjwatson@debian.org>2019-06-05 06:41:44 +0100
commit102062f825fb26a74295a1c089c00c4c4c76b68a (patch)
tree3db66bc8c8483cce66516dff36f6ef56065143d9 /kex.c
parent3d246f10429fc9a37b98eabef94fe8dc7c61002b (diff)
parentfd0fa130ecf06d7d092932adcd5d77f1549bfc8d (diff)
Import openssh_8.0p1.orig.tar.gz
Diffstat (limited to 'kex.c')
-rw-r--r--kex.c350
1 files changed, 310 insertions, 40 deletions
diff --git a/kex.c b/kex.c
index 25f9f66f6..34808b5c3 100644
--- a/kex.c
+++ b/kex.c
@@ -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
580int 589struct kex *
581kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) 590kex_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
607void 605void
@@ -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
664int 666int
667kex_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
679int
665kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) 680kex_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
1019int 1041int
1020kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, 1042kex_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
1060int
1061kex_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)
1037void 1077void
1038dump_digest(char *msg, u_char *digest, int len) 1078dump_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 */
1089static void
1090send_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 */
1109int
1110kex_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