diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 409 |
1 files changed, 28 insertions, 381 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 460d614f0..4ed39a23e 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: sshconnect2.c,v 1.60 2001/03/29 21:06:21 stevesk Exp $"); | 26 | RCSID("$OpenBSD: sshconnect2.c,v 1.61 2001/04/03 19:53:29 markus Exp $"); |
27 | 27 | ||
28 | #include <openssl/bn.h> | 28 | #include <openssl/bn.h> |
29 | #include <openssl/md5.h> | 29 | #include <openssl/md5.h> |
@@ -47,15 +47,12 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.60 2001/03/29 21:06:21 stevesk Exp $"); | |||
47 | #include "authfile.h" | 47 | #include "authfile.h" |
48 | #include "cli.h" | 48 | #include "cli.h" |
49 | #include "dh.h" | 49 | #include "dh.h" |
50 | #include "dispatch.h" | ||
51 | #include "authfd.h" | 50 | #include "authfd.h" |
52 | #include "log.h" | 51 | #include "log.h" |
53 | #include "readconf.h" | 52 | #include "readconf.h" |
54 | #include "readpass.h" | 53 | #include "readpass.h" |
55 | #include "match.h" | 54 | #include "match.h" |
56 | 55 | #include "dispatch.h" | |
57 | void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); | ||
58 | void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); | ||
59 | 56 | ||
60 | /* import */ | 57 | /* import */ |
61 | extern char *client_version_string; | 58 | extern char *client_version_string; |
@@ -69,13 +66,24 @@ extern Options options; | |||
69 | u_char *session_id2 = NULL; | 66 | u_char *session_id2 = NULL; |
70 | int session_id2_len = 0; | 67 | int session_id2_len = 0; |
71 | 68 | ||
69 | char *xxx_host; | ||
70 | struct sockaddr *xxx_hostaddr; | ||
71 | |||
72 | int | ||
73 | check_host_key_callback(Key *hostkey) | ||
74 | { | ||
75 | check_host_key(xxx_host, xxx_hostaddr, hostkey, | ||
76 | options.user_hostfile2, options.system_hostfile2); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
72 | void | 80 | void |
73 | ssh_kex2(char *host, struct sockaddr *hostaddr) | 81 | ssh_kex2(char *host, struct sockaddr *hostaddr) |
74 | { | 82 | { |
75 | int i, plen; | ||
76 | Kex *kex; | 83 | Kex *kex; |
77 | Buffer *client_kexinit, *server_kexinit; | 84 | |
78 | char *sprop[PROPOSAL_MAX]; | 85 | xxx_host = host; |
86 | xxx_hostaddr = hostaddr; | ||
79 | 87 | ||
80 | if (options.ciphers == (char *)-1) { | 88 | if (options.ciphers == (char *)-1) { |
81 | log("No valid ciphers for protocol version 2 given, using defaults."); | 89 | log("No valid ciphers for protocol version 2 given, using defaults."); |
@@ -101,46 +109,13 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
101 | myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; | 109 | myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; |
102 | } | 110 | } |
103 | 111 | ||
104 | /* buffers with raw kexinit messages */ | 112 | kex = kex_start(myproposal); |
105 | server_kexinit = xmalloc(sizeof(*server_kexinit)); | 113 | kex->client_version_string=client_version_string; |
106 | buffer_init(server_kexinit); | 114 | kex->server_version_string=server_version_string; |
107 | client_kexinit = kex_init(myproposal); | 115 | kex->check_host_key=&check_host_key_callback; |
108 | |||
109 | /* algorithm negotiation */ | ||
110 | kex_exchange_kexinit(client_kexinit, server_kexinit, sprop); | ||
111 | kex = kex_choose_conf(myproposal, sprop, 0); | ||
112 | for (i = 0; i < PROPOSAL_MAX; i++) | ||
113 | xfree(sprop[i]); | ||
114 | |||
115 | /* server authentication and session key agreement */ | ||
116 | switch(kex->kex_type) { | ||
117 | case DH_GRP1_SHA1: | ||
118 | ssh_dh1_client(kex, host, hostaddr, | ||
119 | client_kexinit, server_kexinit); | ||
120 | break; | ||
121 | case DH_GEX_SHA1: | ||
122 | ssh_dhgex_client(kex, host, hostaddr, client_kexinit, | ||
123 | server_kexinit); | ||
124 | break; | ||
125 | default: | ||
126 | fatal("Unsupported key exchange %d", kex->kex_type); | ||
127 | } | ||
128 | |||
129 | buffer_free(client_kexinit); | ||
130 | buffer_free(server_kexinit); | ||
131 | xfree(client_kexinit); | ||
132 | xfree(server_kexinit); | ||
133 | 116 | ||
134 | debug("Wait SSH2_MSG_NEWKEYS."); | 117 | /* start key exchange */ |
135 | packet_read_expect(&plen, SSH2_MSG_NEWKEYS); | 118 | dispatch_run(DISPATCH_BLOCK, &kex->newkeys, kex); |
136 | packet_done(); | ||
137 | debug("GOT SSH2_MSG_NEWKEYS."); | ||
138 | |||
139 | debug("send SSH2_MSG_NEWKEYS."); | ||
140 | packet_start(SSH2_MSG_NEWKEYS); | ||
141 | packet_send(); | ||
142 | packet_write_wait(); | ||
143 | debug("done: send SSH2_MSG_NEWKEYS."); | ||
144 | 119 | ||
145 | #ifdef DEBUG_KEXDH | 120 | #ifdef DEBUG_KEXDH |
146 | /* send 1st encrypted/maced/compressed message */ | 121 | /* send 1st encrypted/maced/compressed message */ |
@@ -149,339 +124,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
149 | packet_send(); | 124 | packet_send(); |
150 | packet_write_wait(); | 125 | packet_write_wait(); |
151 | #endif | 126 | #endif |
152 | debug("done: KEX2."); | 127 | debug("done: ssh_kex2."); |
153 | } | ||
154 | |||
155 | /* diffie-hellman-group1-sha1 */ | ||
156 | |||
157 | void | ||
158 | ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr, | ||
159 | Buffer *client_kexinit, Buffer *server_kexinit) | ||
160 | { | ||
161 | #ifdef DEBUG_KEXDH | ||
162 | int i; | ||
163 | #endif | ||
164 | int plen, dlen; | ||
165 | u_int klen, kout; | ||
166 | char *signature = NULL; | ||
167 | u_int slen; | ||
168 | char *server_host_key_blob = NULL; | ||
169 | Key *server_host_key; | ||
170 | u_int sbloblen; | ||
171 | DH *dh; | ||
172 | BIGNUM *dh_server_pub = 0; | ||
173 | BIGNUM *shared_secret = 0; | ||
174 | u_char *kbuf; | ||
175 | u_char *hash; | ||
176 | |||
177 | debug("Sending SSH2_MSG_KEXDH_INIT."); | ||
178 | /* generate and send 'e', client DH public key */ | ||
179 | dh = dh_new_group1(); | ||
180 | dh_gen_key(dh, kex->we_need * 8); | ||
181 | packet_start(SSH2_MSG_KEXDH_INIT); | ||
182 | packet_put_bignum2(dh->pub_key); | ||
183 | packet_send(); | ||
184 | packet_write_wait(); | ||
185 | |||
186 | #ifdef DEBUG_KEXDH | ||
187 | fprintf(stderr, "\np= "); | ||
188 | BN_print_fp(stderr, dh->p); | ||
189 | fprintf(stderr, "\ng= "); | ||
190 | BN_print_fp(stderr, dh->g); | ||
191 | fprintf(stderr, "\npub= "); | ||
192 | BN_print_fp(stderr, dh->pub_key); | ||
193 | fprintf(stderr, "\n"); | ||
194 | DHparams_print_fp(stderr, dh); | ||
195 | #endif | ||
196 | |||
197 | debug("Wait SSH2_MSG_KEXDH_REPLY."); | ||
198 | |||
199 | packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY); | ||
200 | |||
201 | debug("Got SSH2_MSG_KEXDH_REPLY."); | ||
202 | |||
203 | /* key, cert */ | ||
204 | server_host_key_blob = packet_get_string(&sbloblen); | ||
205 | server_host_key = key_from_blob(server_host_key_blob, sbloblen); | ||
206 | if (server_host_key == NULL) | ||
207 | fatal("cannot decode server_host_key_blob"); | ||
208 | |||
209 | check_host_key(host, hostaddr, server_host_key, | ||
210 | options.user_hostfile2, options.system_hostfile2); | ||
211 | |||
212 | /* DH paramter f, server public DH key */ | ||
213 | dh_server_pub = BN_new(); | ||
214 | if (dh_server_pub == NULL) | ||
215 | fatal("dh_server_pub == NULL"); | ||
216 | packet_get_bignum2(dh_server_pub, &dlen); | ||
217 | |||
218 | #ifdef DEBUG_KEXDH | ||
219 | fprintf(stderr, "\ndh_server_pub= "); | ||
220 | BN_print_fp(stderr, dh_server_pub); | ||
221 | fprintf(stderr, "\n"); | ||
222 | debug("bits %d", BN_num_bits(dh_server_pub)); | ||
223 | #endif | ||
224 | |||
225 | /* signed H */ | ||
226 | signature = packet_get_string(&slen); | ||
227 | packet_done(); | ||
228 | |||
229 | if (!dh_pub_is_valid(dh, dh_server_pub)) | ||
230 | packet_disconnect("bad server public DH value"); | ||
231 | |||
232 | klen = DH_size(dh); | ||
233 | kbuf = xmalloc(klen); | ||
234 | kout = DH_compute_key(kbuf, dh_server_pub, dh); | ||
235 | #ifdef DEBUG_KEXDH | ||
236 | debug("shared secret: len %d/%d", klen, kout); | ||
237 | fprintf(stderr, "shared secret == "); | ||
238 | for (i = 0; i< kout; i++) | ||
239 | fprintf(stderr, "%02x", (kbuf[i])&0xff); | ||
240 | fprintf(stderr, "\n"); | ||
241 | #endif | ||
242 | shared_secret = BN_new(); | ||
243 | |||
244 | BN_bin2bn(kbuf, kout, shared_secret); | ||
245 | memset(kbuf, 0, klen); | ||
246 | xfree(kbuf); | ||
247 | |||
248 | /* calc and verify H */ | ||
249 | hash = kex_hash( | ||
250 | client_version_string, | ||
251 | server_version_string, | ||
252 | buffer_ptr(client_kexinit), buffer_len(client_kexinit), | ||
253 | buffer_ptr(server_kexinit), buffer_len(server_kexinit), | ||
254 | server_host_key_blob, sbloblen, | ||
255 | dh->pub_key, | ||
256 | dh_server_pub, | ||
257 | shared_secret | ||
258 | ); | ||
259 | xfree(server_host_key_blob); | ||
260 | DH_free(dh); | ||
261 | BN_free(dh_server_pub); | ||
262 | #ifdef DEBUG_KEXDH | ||
263 | fprintf(stderr, "hash == "); | ||
264 | for (i = 0; i< 20; i++) | ||
265 | fprintf(stderr, "%02x", (hash[i])&0xff); | ||
266 | fprintf(stderr, "\n"); | ||
267 | #endif | ||
268 | if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) | ||
269 | fatal("key_verify failed for server_host_key"); | ||
270 | key_free(server_host_key); | ||
271 | xfree(signature); | ||
272 | |||
273 | kex_derive_keys(kex, hash, shared_secret); | ||
274 | BN_clear_free(shared_secret); | ||
275 | packet_set_kex(kex); | ||
276 | |||
277 | /* save session id */ | ||
278 | session_id2_len = 20; | ||
279 | session_id2 = xmalloc(session_id2_len); | ||
280 | memcpy(session_id2, hash, session_id2_len); | ||
281 | } | ||
282 | |||
283 | /* diffie-hellman-group-exchange-sha1 */ | ||
284 | |||
285 | /* | ||
286 | * Estimates the group order for a Diffie-Hellman group that has an | ||
287 | * attack complexity approximately the same as O(2**bits). Estimate | ||
288 | * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))) | ||
289 | */ | ||
290 | |||
291 | int | ||
292 | dh_estimate(int bits) | ||
293 | { | ||
294 | |||
295 | if (bits < 64) | ||
296 | return (512); /* O(2**63) */ | ||
297 | if (bits < 128) | ||
298 | return (1024); /* O(2**86) */ | ||
299 | if (bits < 192) | ||
300 | return (2048); /* O(2**116) */ | ||
301 | return (4096); /* O(2**156) */ | ||
302 | } | ||
303 | |||
304 | void | ||
305 | ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr, | ||
306 | Buffer *client_kexinit, Buffer *server_kexinit) | ||
307 | { | ||
308 | #ifdef DEBUG_KEXDH | ||
309 | int i; | ||
310 | #endif | ||
311 | int plen, dlen; | ||
312 | u_int klen, kout; | ||
313 | char *signature = NULL; | ||
314 | u_int slen, nbits, min, max; | ||
315 | char *server_host_key_blob = NULL; | ||
316 | Key *server_host_key; | ||
317 | u_int sbloblen; | ||
318 | DH *dh; | ||
319 | BIGNUM *dh_server_pub = 0; | ||
320 | BIGNUM *shared_secret = 0; | ||
321 | BIGNUM *p = 0, *g = 0; | ||
322 | u_char *kbuf; | ||
323 | u_char *hash; | ||
324 | |||
325 | nbits = dh_estimate(kex->we_need * 8); | ||
326 | |||
327 | if (datafellows & SSH_OLD_DHGEX) { | ||
328 | debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST_OLD."); | ||
329 | |||
330 | /* Old GEX request */ | ||
331 | packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); | ||
332 | packet_put_int(nbits); | ||
333 | min = DH_GRP_MIN; | ||
334 | max = DH_GRP_MAX; | ||
335 | } else { | ||
336 | debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST."); | ||
337 | |||
338 | /* New GEX request */ | ||
339 | min = DH_GRP_MIN; | ||
340 | max = DH_GRP_MAX; | ||
341 | |||
342 | packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); | ||
343 | packet_put_int(min); | ||
344 | packet_put_int(nbits); | ||
345 | packet_put_int(max); | ||
346 | } | ||
347 | packet_send(); | ||
348 | packet_write_wait(); | ||
349 | |||
350 | #ifdef DEBUG_KEXDH | ||
351 | fprintf(stderr, "\nmin = %d, nbits = %d, max = %d", min, nbits, max); | ||
352 | #endif | ||
353 | |||
354 | debug("Wait SSH2_MSG_KEX_DH_GEX_GROUP."); | ||
355 | |||
356 | packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP); | ||
357 | |||
358 | debug("Got SSH2_MSG_KEX_DH_GEX_GROUP."); | ||
359 | |||
360 | if ((p = BN_new()) == NULL) | ||
361 | fatal("BN_new"); | ||
362 | packet_get_bignum2(p, &dlen); | ||
363 | if ((g = BN_new()) == NULL) | ||
364 | fatal("BN_new"); | ||
365 | packet_get_bignum2(g, &dlen); | ||
366 | |||
367 | if (BN_num_bits(p) < min || BN_num_bits(p) > max) | ||
368 | fatal("DH_GEX group out of range: %d !< %d !< %d", | ||
369 | min, BN_num_bits(p), max); | ||
370 | |||
371 | dh = dh_new_group(g, p); | ||
372 | |||
373 | dh_gen_key(dh, kex->we_need * 8); | ||
374 | |||
375 | #ifdef DEBUG_KEXDH | ||
376 | fprintf(stderr, "\np= "); | ||
377 | BN_print_fp(stderr, dh->p); | ||
378 | fprintf(stderr, "\ng= "); | ||
379 | BN_print_fp(stderr, dh->g); | ||
380 | fprintf(stderr, "\npub= "); | ||
381 | BN_print_fp(stderr, dh->pub_key); | ||
382 | fprintf(stderr, "\n"); | ||
383 | DHparams_print_fp(stderr, dh); | ||
384 | #endif | ||
385 | |||
386 | debug("Sending SSH2_MSG_KEX_DH_GEX_INIT."); | ||
387 | /* generate and send 'e', client DH public key */ | ||
388 | packet_start(SSH2_MSG_KEX_DH_GEX_INIT); | ||
389 | packet_put_bignum2(dh->pub_key); | ||
390 | packet_send(); | ||
391 | packet_write_wait(); | ||
392 | |||
393 | debug("Wait SSH2_MSG_KEX_DH_GEX_REPLY."); | ||
394 | |||
395 | packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY); | ||
396 | |||
397 | debug("Got SSH2_MSG_KEXDH_REPLY."); | ||
398 | |||
399 | /* key, cert */ | ||
400 | server_host_key_blob = packet_get_string(&sbloblen); | ||
401 | server_host_key = key_from_blob(server_host_key_blob, sbloblen); | ||
402 | if (server_host_key == NULL) | ||
403 | fatal("cannot decode server_host_key_blob"); | ||
404 | |||
405 | check_host_key(host, hostaddr, server_host_key, | ||
406 | options.user_hostfile2, options.system_hostfile2); | ||
407 | |||
408 | /* DH paramter f, server public DH key */ | ||
409 | dh_server_pub = BN_new(); | ||
410 | if (dh_server_pub == NULL) | ||
411 | fatal("dh_server_pub == NULL"); | ||
412 | packet_get_bignum2(dh_server_pub, &dlen); | ||
413 | |||
414 | #ifdef DEBUG_KEXDH | ||
415 | fprintf(stderr, "\ndh_server_pub= "); | ||
416 | BN_print_fp(stderr, dh_server_pub); | ||
417 | fprintf(stderr, "\n"); | ||
418 | debug("bits %d", BN_num_bits(dh_server_pub)); | ||
419 | #endif | ||
420 | |||
421 | /* signed H */ | ||
422 | signature = packet_get_string(&slen); | ||
423 | packet_done(); | ||
424 | |||
425 | if (!dh_pub_is_valid(dh, dh_server_pub)) | ||
426 | packet_disconnect("bad server public DH value"); | ||
427 | |||
428 | klen = DH_size(dh); | ||
429 | kbuf = xmalloc(klen); | ||
430 | kout = DH_compute_key(kbuf, dh_server_pub, dh); | ||
431 | #ifdef DEBUG_KEXDH | ||
432 | debug("shared secret: len %d/%d", klen, kout); | ||
433 | fprintf(stderr, "shared secret == "); | ||
434 | for (i = 0; i< kout; i++) | ||
435 | fprintf(stderr, "%02x", (kbuf[i])&0xff); | ||
436 | fprintf(stderr, "\n"); | ||
437 | #endif | ||
438 | shared_secret = BN_new(); | ||
439 | |||
440 | BN_bin2bn(kbuf, kout, shared_secret); | ||
441 | memset(kbuf, 0, klen); | ||
442 | xfree(kbuf); | ||
443 | |||
444 | if (datafellows & SSH_OLD_DHGEX) { | ||
445 | /* These values are not included in the hash */ | ||
446 | min = -1; | ||
447 | max = -1; | ||
448 | } | ||
449 | |||
450 | /* calc and verify H */ | ||
451 | hash = kex_hash_gex( | ||
452 | client_version_string, | ||
453 | server_version_string, | ||
454 | buffer_ptr(client_kexinit), buffer_len(client_kexinit), | ||
455 | buffer_ptr(server_kexinit), buffer_len(server_kexinit), | ||
456 | server_host_key_blob, sbloblen, | ||
457 | min, nbits, max, | ||
458 | dh->p, dh->g, | ||
459 | dh->pub_key, | ||
460 | dh_server_pub, | ||
461 | shared_secret | ||
462 | ); | ||
463 | xfree(server_host_key_blob); | ||
464 | DH_free(dh); | ||
465 | BN_free(dh_server_pub); | ||
466 | #ifdef DEBUG_KEXDH | ||
467 | fprintf(stderr, "hash == "); | ||
468 | for (i = 0; i< 20; i++) | ||
469 | fprintf(stderr, "%02x", (hash[i])&0xff); | ||
470 | fprintf(stderr, "\n"); | ||
471 | #endif | ||
472 | if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) | ||
473 | fatal("key_verify failed for server_host_key"); | ||
474 | key_free(server_host_key); | ||
475 | xfree(signature); | ||
476 | |||
477 | kex_derive_keys(kex, hash, shared_secret); | ||
478 | BN_clear_free(shared_secret); | ||
479 | packet_set_kex(kex); | ||
480 | |||
481 | /* save session id */ | ||
482 | session_id2_len = 20; | ||
483 | session_id2 = xmalloc(session_id2_len); | ||
484 | memcpy(session_id2, hash, session_id2_len); | ||
485 | } | 128 | } |
486 | 129 | ||
487 | /* | 130 | /* |
@@ -563,6 +206,7 @@ ssh_userauth2(const char *server_user, char *host) | |||
563 | Authctxt authctxt; | 206 | Authctxt authctxt; |
564 | int type; | 207 | int type; |
565 | int plen; | 208 | int plen; |
209 | int i; | ||
566 | 210 | ||
567 | if (options.challenge_reponse_authentication) | 211 | if (options.challenge_reponse_authentication) |
568 | options.kbd_interactive_authentication = 1; | 212 | options.kbd_interactive_authentication = 1; |
@@ -603,7 +247,10 @@ ssh_userauth2(const char *server_user, char *host) | |||
603 | /* initial userauth request */ | 247 | /* initial userauth request */ |
604 | userauth_none(&authctxt); | 248 | userauth_none(&authctxt); |
605 | 249 | ||
606 | dispatch_init(&input_userauth_error); | 250 | //dispatch_init(&input_userauth_error); |
251 | for (i = 50; i <= 254; i++) { | ||
252 | dispatch_set(i, &input_userauth_error); | ||
253 | } | ||
607 | dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); | 254 | dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); |
608 | dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); | 255 | dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); |
609 | dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); | 256 | dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); |