diff options
author | Damien Miller <djm@mindrot.org> | 2000-04-12 18:45:05 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2000-04-12 18:45:05 +1000 |
commit | efb4afe0265333ce554f699c2a19ae249dd8d1b5 (patch) | |
tree | 8fe5e0bb9791e7fa3d1788084ae669f7a9dcd2e0 /sshd.c | |
parent | 11e37f638d3cc064371521001eaeb2d75bfe4a8d (diff) |
- More large OpenBSD CVS updates:
- [auth.c auth.h servconf.c servconf.h serverloop.c session.c]
[session.h ssh.h sshd.c README.openssh2]
ssh2 server side, see README.openssh2; enable with 'sshd -2'
- [channels.c]
no adjust after close
- [sshd.c compat.c ]
interop w/ latest ssh.com windows client.
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 240 |
1 files changed, 233 insertions, 7 deletions
@@ -8,10 +8,13 @@ | |||
8 | * information to/from the application to the user client over an encrypted | 8 | * information to/from the application to the user client over an encrypted |
9 | * connection. This can also handle forwarding of X11, TCP/IP, and authentication | 9 | * connection. This can also handle forwarding of X11, TCP/IP, and authentication |
10 | * agent connections. | 10 | * agent connections. |
11 | * | ||
12 | * SSH2 implementation, | ||
13 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | ||
11 | */ | 14 | */ |
12 | 15 | ||
13 | #include "includes.h" | 16 | #include "includes.h" |
14 | RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $"); | 17 | RCSID("$OpenBSD: sshd.c,v 1.99 2000/04/07 09:17:39 markus Exp $"); |
15 | 18 | ||
16 | #include "xmalloc.h" | 19 | #include "xmalloc.h" |
17 | #include "rsa.h" | 20 | #include "rsa.h" |
@@ -25,6 +28,7 @@ RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $"); | |||
25 | #include "compat.h" | 28 | #include "compat.h" |
26 | #include "buffer.h" | 29 | #include "buffer.h" |
27 | 30 | ||
31 | #include "ssh2.h" | ||
28 | #ifdef HAVE_OPENSSL | 32 | #ifdef HAVE_OPENSSL |
29 | # include <openssl/dh.h> | 33 | # include <openssl/dh.h> |
30 | # include <openssl/bn.h> | 34 | # include <openssl/bn.h> |
@@ -39,9 +43,12 @@ RCSID("$OpenBSD: sshd.c,v 1.97 2000/04/04 21:37:27 markus Exp $"); | |||
39 | # include <ssl/dsa.h> | 43 | # include <ssl/dsa.h> |
40 | # include <ssl/rsa.h> | 44 | # include <ssl/rsa.h> |
41 | #endif | 45 | #endif |
46 | #include "kex.h" | ||
42 | #include "key.h" | 47 | #include "key.h" |
48 | #include "dsa.h" | ||
43 | 49 | ||
44 | #include "auth.h" | 50 | #include "auth.h" |
51 | #include "myproposal.h" | ||
45 | 52 | ||
46 | #ifdef LIBWRAP | 53 | #ifdef LIBWRAP |
47 | #include <tcpd.h> | 54 | #include <tcpd.h> |
@@ -70,6 +77,9 @@ int IPv4or6 = AF_INET; | |||
70 | int IPv4or6 = AF_UNSPEC; | 77 | int IPv4or6 = AF_UNSPEC; |
71 | #endif | 78 | #endif |
72 | 79 | ||
80 | /* Flag indicating whether SSH2 is enabled */ | ||
81 | int allow_ssh2 = 0; | ||
82 | |||
73 | /* | 83 | /* |
74 | * Debug mode flag. This can be set on the command line. If debug | 84 | * Debug mode flag. This can be set on the command line. If debug |
75 | * mode is enabled, extra debugging output will be sent to the system | 85 | * mode is enabled, extra debugging output will be sent to the system |
@@ -136,6 +146,7 @@ unsigned char session_id[16]; | |||
136 | 146 | ||
137 | /* Prototypes for various functions defined later in this file. */ | 147 | /* Prototypes for various functions defined later in this file. */ |
138 | void do_ssh1_kex(); | 148 | void do_ssh1_kex(); |
149 | void do_ssh2_kex(); | ||
139 | 150 | ||
140 | /* | 151 | /* |
141 | * Close all listening sockets | 152 | * Close all listening sockets |
@@ -255,6 +266,21 @@ key_regeneration_alarm(int sig) | |||
255 | errno = save_errno; | 266 | errno = save_errno; |
256 | } | 267 | } |
257 | 268 | ||
269 | char * | ||
270 | chop(char *s) | ||
271 | { | ||
272 | char *t = s; | ||
273 | while (*t) { | ||
274 | if(*t == '\n' || *t == '\r') { | ||
275 | *t = '\0'; | ||
276 | return s; | ||
277 | } | ||
278 | t++; | ||
279 | } | ||
280 | return s; | ||
281 | |||
282 | } | ||
283 | |||
258 | void | 284 | void |
259 | sshd_exchange_identification(int sock_in, int sock_out) | 285 | sshd_exchange_identification(int sock_in, int sock_out) |
260 | { | 286 | { |
@@ -265,7 +291,9 @@ sshd_exchange_identification(int sock_in, int sock_out) | |||
265 | char remote_version[256]; /* Must be at least as big as buf. */ | 291 | char remote_version[256]; /* Must be at least as big as buf. */ |
266 | 292 | ||
267 | snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", | 293 | snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", |
268 | PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); | 294 | allow_ssh2 ? 1 : PROTOCOL_MAJOR, |
295 | allow_ssh2 ? 99 : PROTOCOL_MINOR, | ||
296 | SSH_VERSION); | ||
269 | server_version_string = xstrdup(buf); | 297 | server_version_string = xstrdup(buf); |
270 | 298 | ||
271 | if (client_version_string == NULL) { | 299 | if (client_version_string == NULL) { |
@@ -286,7 +314,7 @@ sshd_exchange_identification(int sock_in, int sock_out) | |||
286 | buf[i] = '\n'; | 314 | buf[i] = '\n'; |
287 | buf[i + 1] = 0; | 315 | buf[i + 1] = 0; |
288 | continue; | 316 | continue; |
289 | /*break; XXX eat \r */ | 317 | //break; |
290 | } | 318 | } |
291 | if (buf[i] == '\n') { | 319 | if (buf[i] == '\n') { |
292 | /* buf[i] == '\n' */ | 320 | /* buf[i] == '\n' */ |
@@ -315,6 +343,8 @@ sshd_exchange_identification(int sock_in, int sock_out) | |||
315 | debug("Client protocol version %d.%d; client software version %.100s", | 343 | debug("Client protocol version %d.%d; client software version %.100s", |
316 | remote_major, remote_minor, remote_version); | 344 | remote_major, remote_minor, remote_version); |
317 | 345 | ||
346 | compat_datafellows(remote_version); | ||
347 | |||
318 | switch(remote_major) { | 348 | switch(remote_major) { |
319 | case 1: | 349 | case 1: |
320 | if (remote_minor < 3) { | 350 | if (remote_minor < 3) { |
@@ -324,7 +354,15 @@ sshd_exchange_identification(int sock_in, int sock_out) | |||
324 | /* note that this disables agent-forwarding */ | 354 | /* note that this disables agent-forwarding */ |
325 | enable_compat13(); | 355 | enable_compat13(); |
326 | } | 356 | } |
327 | break; | 357 | if (remote_minor != 99) |
358 | break; | ||
359 | /* FALLTHROUGH */ | ||
360 | case 2: | ||
361 | if (allow_ssh2) { | ||
362 | enable_compat20(); | ||
363 | break; | ||
364 | } | ||
365 | /* FALLTHROUGH */ | ||
328 | default: | 366 | default: |
329 | s = "Protocol major versions differ.\n"; | 367 | s = "Protocol major versions differ.\n"; |
330 | (void) atomicio(write, sock_out, s, strlen(s)); | 368 | (void) atomicio(write, sock_out, s, strlen(s)); |
@@ -335,6 +373,8 @@ sshd_exchange_identification(int sock_in, int sock_out) | |||
335 | fatal_cleanup(); | 373 | fatal_cleanup(); |
336 | break; | 374 | break; |
337 | } | 375 | } |
376 | chop(server_version_string); | ||
377 | chop(client_version_string); | ||
338 | } | 378 | } |
339 | 379 | ||
340 | /* | 380 | /* |
@@ -370,8 +410,11 @@ main(int ac, char **av) | |||
370 | initialize_server_options(&options); | 410 | initialize_server_options(&options); |
371 | 411 | ||
372 | /* Parse command-line arguments. */ | 412 | /* Parse command-line arguments. */ |
373 | while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ46")) != EOF) { | 413 | while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ246")) != EOF) { |
374 | switch (opt) { | 414 | switch (opt) { |
415 | case '2': | ||
416 | allow_ssh2 = 1; | ||
417 | break; | ||
375 | case '4': | 418 | case '4': |
376 | IPv4or6 = AF_INET; | 419 | IPv4or6 = AF_INET; |
377 | break; | 420 | break; |
@@ -837,9 +880,14 @@ main(int ac, char **av) | |||
837 | packet_set_nonblocking(); | 880 | packet_set_nonblocking(); |
838 | 881 | ||
839 | /* perform the key exchange */ | 882 | /* perform the key exchange */ |
840 | do_ssh1_kex(); | ||
841 | /* authenticate user and start session */ | 883 | /* authenticate user and start session */ |
842 | do_authentication(); | 884 | if (compat20) { |
885 | do_ssh2_kex(); | ||
886 | do_authentication2(); | ||
887 | } else { | ||
888 | do_ssh1_kex(); | ||
889 | do_authentication(); | ||
890 | } | ||
843 | 891 | ||
844 | #ifdef KRB4 | 892 | #ifdef KRB4 |
845 | /* Cleanup user's ticket cache file. */ | 893 | /* Cleanup user's ticket cache file. */ |
@@ -1049,3 +1097,181 @@ do_ssh1_kex() | |||
1049 | packet_send(); | 1097 | packet_send(); |
1050 | packet_write_wait(); | 1098 | packet_write_wait(); |
1051 | } | 1099 | } |
1100 | |||
1101 | /* | ||
1102 | * SSH2 key exchange: diffie-hellman-group1-sha1 | ||
1103 | */ | ||
1104 | void | ||
1105 | do_ssh2_kex() | ||
1106 | { | ||
1107 | Buffer *server_kexinit; | ||
1108 | Buffer *client_kexinit; | ||
1109 | int payload_len, dlen; | ||
1110 | int slen; | ||
1111 | unsigned int klen, kout; | ||
1112 | char *ptr; | ||
1113 | unsigned char *signature = NULL; | ||
1114 | unsigned char *server_host_key_blob = NULL; | ||
1115 | unsigned int sbloblen; | ||
1116 | DH *dh; | ||
1117 | BIGNUM *dh_client_pub = 0; | ||
1118 | BIGNUM *shared_secret = 0; | ||
1119 | int i; | ||
1120 | unsigned char *kbuf; | ||
1121 | unsigned char *hash; | ||
1122 | Kex *kex; | ||
1123 | Key *server_host_key; | ||
1124 | char *cprop[PROPOSAL_MAX]; | ||
1125 | char *sprop[PROPOSAL_MAX]; | ||
1126 | |||
1127 | /* KEXINIT */ | ||
1128 | |||
1129 | debug("Sending KEX init."); | ||
1130 | |||
1131 | for (i = 0; i < PROPOSAL_MAX; i++) | ||
1132 | sprop[i] = xstrdup(myproposal[i]); | ||
1133 | server_kexinit = kex_init(sprop); | ||
1134 | packet_start(SSH2_MSG_KEXINIT); | ||
1135 | packet_put_raw(buffer_ptr(server_kexinit), buffer_len(server_kexinit)); | ||
1136 | packet_send(); | ||
1137 | packet_write_wait(); | ||
1138 | |||
1139 | debug("done"); | ||
1140 | |||
1141 | packet_read_expect(&payload_len, SSH2_MSG_KEXINIT); | ||
1142 | |||
1143 | /* | ||
1144 | * save raw KEXINIT payload in buffer. this is used during | ||
1145 | * computation of the session_id and the session keys. | ||
1146 | */ | ||
1147 | client_kexinit = xmalloc(sizeof(*client_kexinit)); | ||
1148 | buffer_init(client_kexinit); | ||
1149 | ptr = packet_get_raw(&payload_len); | ||
1150 | buffer_append(client_kexinit, ptr, payload_len); | ||
1151 | |||
1152 | /* skip cookie */ | ||
1153 | for (i = 0; i < 16; i++) | ||
1154 | (void) packet_get_char(); | ||
1155 | /* save kex init proposal strings */ | ||
1156 | for (i = 0; i < PROPOSAL_MAX; i++) { | ||
1157 | cprop[i] = packet_get_string(NULL); | ||
1158 | debug("got kexinit string: %s", cprop[i]); | ||
1159 | } | ||
1160 | |||
1161 | i = (int) packet_get_char(); | ||
1162 | debug("first kex follow == %d", i); | ||
1163 | i = packet_get_int(); | ||
1164 | debug("reserved == %d", i); | ||
1165 | |||
1166 | debug("done read kexinit"); | ||
1167 | kex = kex_choose_conf(cprop, sprop, 1); | ||
1168 | |||
1169 | /* KEXDH */ | ||
1170 | |||
1171 | debug("Wait SSH2_MSG_KEXDH_INIT."); | ||
1172 | packet_read_expect(&payload_len, SSH2_MSG_KEXDH_INIT); | ||
1173 | |||
1174 | /* key, cert */ | ||
1175 | dh_client_pub = BN_new(); | ||
1176 | if (dh_client_pub == NULL) | ||
1177 | fatal("dh_client_pub == NULL"); | ||
1178 | packet_get_bignum2(dh_client_pub, &dlen); | ||
1179 | |||
1180 | #ifdef DEBUG_KEXDH | ||
1181 | fprintf(stderr, "\ndh_client_pub= "); | ||
1182 | bignum_print(dh_client_pub); | ||
1183 | fprintf(stderr, "\n"); | ||
1184 | debug("bits %d", BN_num_bits(dh_client_pub)); | ||
1185 | #endif | ||
1186 | |||
1187 | /* generate DH key */ | ||
1188 | dh = new_dh_group1(); /* XXX depends on 'kex' */ | ||
1189 | |||
1190 | #ifdef DEBUG_KEXDH | ||
1191 | fprintf(stderr, "\np= "); | ||
1192 | bignum_print(dh->p); | ||
1193 | fprintf(stderr, "\ng= "); | ||
1194 | bignum_print(dh->g); | ||
1195 | fprintf(stderr, "\npub= "); | ||
1196 | bignum_print(dh->pub_key); | ||
1197 | fprintf(stderr, "\n"); | ||
1198 | #endif | ||
1199 | |||
1200 | klen = DH_size(dh); | ||
1201 | kbuf = xmalloc(klen); | ||
1202 | kout = DH_compute_key(kbuf, dh_client_pub, dh); | ||
1203 | |||
1204 | #ifdef DEBUG_KEXDH | ||
1205 | debug("shared secret: len %d/%d", klen, kout); | ||
1206 | fprintf(stderr, "shared secret == "); | ||
1207 | for (i = 0; i< kout; i++) | ||
1208 | fprintf(stderr, "%02x", (kbuf[i])&0xff); | ||
1209 | fprintf(stderr, "\n"); | ||
1210 | #endif | ||
1211 | shared_secret = BN_new(); | ||
1212 | |||
1213 | BN_bin2bn(kbuf, kout, shared_secret); | ||
1214 | memset(kbuf, 0, klen); | ||
1215 | xfree(kbuf); | ||
1216 | |||
1217 | server_host_key = dsa_get_serverkey(options.dsa_key_file); | ||
1218 | dsa_make_serverkey_blob(server_host_key, &server_host_key_blob, &sbloblen); | ||
1219 | |||
1220 | /* calc H */ /* XXX depends on 'kex' */ | ||
1221 | hash = kex_hash( | ||
1222 | client_version_string, | ||
1223 | server_version_string, | ||
1224 | buffer_ptr(client_kexinit), buffer_len(client_kexinit), | ||
1225 | buffer_ptr(server_kexinit), buffer_len(server_kexinit), | ||
1226 | (char *)server_host_key_blob, sbloblen, | ||
1227 | dh_client_pub, | ||
1228 | dh->pub_key, | ||
1229 | shared_secret | ||
1230 | ); | ||
1231 | buffer_free(client_kexinit); | ||
1232 | buffer_free(server_kexinit); | ||
1233 | xfree(client_kexinit); | ||
1234 | xfree(server_kexinit); | ||
1235 | #ifdef DEBUG_KEXDH | ||
1236 | fprintf(stderr, "hash == "); | ||
1237 | for (i = 0; i< 20; i++) | ||
1238 | fprintf(stderr, "%02x", (hash[i])&0xff); | ||
1239 | fprintf(stderr, "\n"); | ||
1240 | #endif | ||
1241 | /* sign H */ | ||
1242 | dsa_sign(server_host_key, &signature, &slen, hash, 20); | ||
1243 | /* hashlen depends on KEX */ | ||
1244 | key_free(server_host_key); | ||
1245 | |||
1246 | /* send server hostkey, DH pubkey 'f' and singed H */ | ||
1247 | packet_start(SSH2_MSG_KEXDH_REPLY); | ||
1248 | packet_put_string((char *)server_host_key_blob, sbloblen); | ||
1249 | packet_put_bignum2(dh->pub_key); // f | ||
1250 | packet_put_string((char *)signature, slen); | ||
1251 | packet_send(); | ||
1252 | packet_write_wait(); | ||
1253 | |||
1254 | kex_derive_keys(kex, hash, shared_secret); | ||
1255 | packet_set_kex(kex); | ||
1256 | |||
1257 | /* have keys, free DH */ | ||
1258 | DH_free(dh); | ||
1259 | |||
1260 | debug("send SSH2_MSG_NEWKEYS."); | ||
1261 | packet_start(SSH2_MSG_NEWKEYS); | ||
1262 | packet_send(); | ||
1263 | packet_write_wait(); | ||
1264 | debug("done: send SSH2_MSG_NEWKEYS."); | ||
1265 | |||
1266 | debug("Wait SSH2_MSG_NEWKEYS."); | ||
1267 | packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS); | ||
1268 | debug("GOT SSH2_MSG_NEWKEYS."); | ||
1269 | |||
1270 | /* send 1st encrypted/maced/compressed message */ | ||
1271 | packet_start(SSH2_MSG_IGNORE); | ||
1272 | packet_put_cstring("markus"); | ||
1273 | packet_send(); | ||
1274 | packet_write_wait(); | ||
1275 | |||
1276 | debug("done: KEX2."); | ||
1277 | } | ||