diff options
author | markus@openbsd.org <markus@openbsd.org> | 2015-01-19 20:32:39 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2015-01-20 09:24:11 +1100 |
commit | 3f797653748e7c2b037dacb57574c01d9ef3b4d3 (patch) | |
tree | 8328e3436767e33e6274be3eaa31474da9792bd2 | |
parent | f582f0e917bb0017b00944783cd5f408bf4b0b5e (diff) |
upstream commit
switch ssh-keyscan from setjmp to multiple ssh transport
layer instances ok djm@
-rw-r--r-- | ssh-keyscan.c | 149 |
1 files changed, 81 insertions, 68 deletions
diff --git a/ssh-keyscan.c b/ssh-keyscan.c index 223ac58f1..e02a3bbb1 100644 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keyscan.c,v 1.94 2015/01/19 20:16:15 markus Exp $ */ | 1 | /* $OpenBSD: ssh-keyscan.c,v 1.95 2015/01/19 20:32:39 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. | 3 | * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. |
4 | * | 4 | * |
@@ -24,7 +24,6 @@ | |||
24 | 24 | ||
25 | #include <netdb.h> | 25 | #include <netdb.h> |
26 | #include <errno.h> | 26 | #include <errno.h> |
27 | #include <setjmp.h> | ||
28 | #include <stdarg.h> | 27 | #include <stdarg.h> |
29 | #include <stdio.h> | 28 | #include <stdio.h> |
30 | #include <stdlib.h> | 29 | #include <stdlib.h> |
@@ -35,8 +34,8 @@ | |||
35 | #include "xmalloc.h" | 34 | #include "xmalloc.h" |
36 | #include "ssh.h" | 35 | #include "ssh.h" |
37 | #include "ssh1.h" | 36 | #include "ssh1.h" |
38 | #include "buffer.h" | 37 | #include "sshbuf.h" |
39 | #include "key.h" | 38 | #include "sshkey.h" |
40 | #include "cipher.h" | 39 | #include "cipher.h" |
41 | #include "kex.h" | 40 | #include "kex.h" |
42 | #include "compat.h" | 41 | #include "compat.h" |
@@ -47,6 +46,8 @@ | |||
47 | #include "atomicio.h" | 46 | #include "atomicio.h" |
48 | #include "misc.h" | 47 | #include "misc.h" |
49 | #include "hostfile.h" | 48 | #include "hostfile.h" |
49 | #include "ssherr.h" | ||
50 | #include "ssh_api.h" | ||
50 | 51 | ||
51 | /* Flag indicating whether IPv4 or IPv6. This can be set on the command line. | 52 | /* Flag indicating whether IPv4 or IPv6. This can be set on the command line. |
52 | Default value is AF_UNSPEC means both IPv4 and IPv6. */ | 53 | Default value is AF_UNSPEC means both IPv4 and IPv6. */ |
@@ -76,9 +77,6 @@ extern char *__progname; | |||
76 | fd_set *read_wait; | 77 | fd_set *read_wait; |
77 | size_t read_wait_nfdset; | 78 | size_t read_wait_nfdset; |
78 | int ncon; | 79 | int ncon; |
79 | int nonfatal_fatal = 0; | ||
80 | jmp_buf kexjmp; | ||
81 | Key *kexjmp_key; | ||
82 | 80 | ||
83 | /* | 81 | /* |
84 | * Keep a connection structure for each file descriptor. The state | 82 | * Keep a connection structure for each file descriptor. The state |
@@ -95,12 +93,13 @@ typedef struct Connection { | |||
95 | int c_len; /* Total bytes which must be read. */ | 93 | int c_len; /* Total bytes which must be read. */ |
96 | int c_off; /* Length of data read so far. */ | 94 | int c_off; /* Length of data read so far. */ |
97 | int c_keytype; /* Only one of KT_RSA1, KT_DSA, or KT_RSA */ | 95 | int c_keytype; /* Only one of KT_RSA1, KT_DSA, or KT_RSA */ |
96 | int c_done; /* SSH2 done */ | ||
98 | char *c_namebase; /* Address to free for c_name and c_namelist */ | 97 | char *c_namebase; /* Address to free for c_name and c_namelist */ |
99 | char *c_name; /* Hostname of connection for errors */ | 98 | char *c_name; /* Hostname of connection for errors */ |
100 | char *c_namelist; /* Pointer to other possible addresses */ | 99 | char *c_namelist; /* Pointer to other possible addresses */ |
101 | char *c_output_name; /* Hostname of connection for output */ | 100 | char *c_output_name; /* Hostname of connection for output */ |
102 | char *c_data; /* Data read from this fd */ | 101 | char *c_data; /* Data read from this fd */ |
103 | struct kex *c_kex; /* The key-exchange struct for ssh2 */ | 102 | struct ssh *c_ssh; /* SSH-connection */ |
104 | struct timeval c_tv; /* Time at which connection gets aborted */ | 103 | struct timeval c_tv; /* Time at which connection gets aborted */ |
105 | TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */ | 104 | TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */ |
106 | } con; | 105 | } con; |
@@ -108,6 +107,8 @@ typedef struct Connection { | |||
108 | TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */ | 107 | TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */ |
109 | con *fdcon; | 108 | con *fdcon; |
110 | 109 | ||
110 | static void keyprint(con *c, struct sshkey *key); | ||
111 | |||
111 | static int | 112 | static int |
112 | fdlim_get(int hard) | 113 | fdlim_get(int hard) |
113 | { | 114 | { |
@@ -185,46 +186,61 @@ strnnsep(char **stringp, char *delim) | |||
185 | } | 186 | } |
186 | 187 | ||
187 | #ifdef WITH_SSH1 | 188 | #ifdef WITH_SSH1 |
188 | static Key * | 189 | static struct sshkey * |
189 | keygrab_ssh1(con *c) | 190 | keygrab_ssh1(con *c) |
190 | { | 191 | { |
191 | static Key *rsa; | 192 | static struct sshkey *rsa; |
192 | static Buffer msg; | 193 | static struct sshbuf *msg; |
194 | int r; | ||
195 | u_char type; | ||
193 | 196 | ||
194 | if (rsa == NULL) { | 197 | if (rsa == NULL) { |
195 | buffer_init(&msg); | 198 | if ((rsa = sshkey_new(KEY_RSA1)) == NULL) { |
196 | rsa = key_new(KEY_RSA1); | 199 | error("%s: sshkey_new failed", __func__); |
200 | return NULL; | ||
201 | } | ||
202 | if ((msg = sshbuf_new()) == NULL) | ||
203 | fatal("%s: sshbuf_new failed", __func__); | ||
197 | } | 204 | } |
198 | buffer_append(&msg, c->c_data, c->c_plen); | 205 | if ((r = sshbuf_put(msg, c->c_data, c->c_plen)) != 0 || |
199 | buffer_consume(&msg, 8 - (c->c_plen & 7)); /* padding */ | 206 | (r = sshbuf_consume(msg, 8 - (c->c_plen & 7))) != 0 || /* padding */ |
200 | if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) { | 207 | (r = sshbuf_get_u8(msg, &type)) != 0) |
208 | goto buf_err; | ||
209 | if (type != (int) SSH_SMSG_PUBLIC_KEY) { | ||
201 | error("%s: invalid packet type", c->c_name); | 210 | error("%s: invalid packet type", c->c_name); |
202 | buffer_clear(&msg); | 211 | sshbuf_reset(msg); |
212 | return NULL; | ||
213 | } | ||
214 | if ((r = sshbuf_consume(msg, 8)) != 0 || /* cookie */ | ||
215 | /* server key */ | ||
216 | (r = sshbuf_get_u32(msg, NULL)) != 0 || | ||
217 | (r = sshbuf_get_bignum1(msg, NULL)) != 0 || | ||
218 | (r = sshbuf_get_bignum1(msg, NULL)) != 0 || | ||
219 | /* host key */ | ||
220 | (r = sshbuf_get_u32(msg, NULL)) != 0 || | ||
221 | (r = sshbuf_get_bignum1(msg, rsa->rsa->e)) != 0 || | ||
222 | (r = sshbuf_get_bignum1(msg, rsa->rsa->n)) != 0) { | ||
223 | buf_err: | ||
224 | error("%s: buffer error: %s", __func__, ssh_err(r)); | ||
225 | sshbuf_reset(msg); | ||
203 | return NULL; | 226 | return NULL; |
204 | } | 227 | } |
205 | buffer_consume(&msg, 8); /* cookie */ | ||
206 | |||
207 | /* server key */ | ||
208 | (void) buffer_get_int(&msg); | ||
209 | buffer_get_bignum(&msg, rsa->rsa->e); | ||
210 | buffer_get_bignum(&msg, rsa->rsa->n); | ||
211 | |||
212 | /* host key */ | ||
213 | (void) buffer_get_int(&msg); | ||
214 | buffer_get_bignum(&msg, rsa->rsa->e); | ||
215 | buffer_get_bignum(&msg, rsa->rsa->n); | ||
216 | 228 | ||
217 | buffer_clear(&msg); | 229 | sshbuf_reset(msg); |
218 | 230 | ||
219 | return (rsa); | 231 | return (rsa); |
220 | } | 232 | } |
221 | #endif | 233 | #endif |
222 | 234 | ||
223 | static int | 235 | static int |
224 | hostjump(Key *hostkey, struct ssh *ssh) | 236 | key_print_wrapper(struct sshkey *hostkey, struct ssh *ssh) |
225 | { | 237 | { |
226 | kexjmp_key = hostkey; | 238 | con *c; |
227 | longjmp(kexjmp, 1); | 239 | |
240 | if ((c = ssh_get_app_data(ssh)) != NULL) | ||
241 | keyprint(c, hostkey); | ||
242 | /* always abort key exchange */ | ||
243 | return -1; | ||
228 | } | 244 | } |
229 | 245 | ||
230 | static int | 246 | static int |
@@ -243,48 +259,41 @@ ssh2_capable(int remote_major, int remote_minor) | |||
243 | return 0; | 259 | return 0; |
244 | } | 260 | } |
245 | 261 | ||
246 | static Key * | 262 | static void |
247 | keygrab_ssh2(con *c) | 263 | keygrab_ssh2(con *c) |
248 | { | 264 | { |
249 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; | 265 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; |
250 | int r, j; | 266 | int r; |
251 | 267 | ||
252 | packet_set_connection(c->c_fd, c->c_fd); | ||
253 | enable_compat20(); | 268 | enable_compat20(); |
254 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = | 269 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = |
255 | c->c_keytype == KT_DSA ? "ssh-dss" : | 270 | c->c_keytype == KT_DSA ? "ssh-dss" : |
256 | (c->c_keytype == KT_RSA ? "ssh-rsa" : | 271 | (c->c_keytype == KT_RSA ? "ssh-rsa" : |
257 | (c->c_keytype == KT_ED25519 ? "ssh-ed25519" : | 272 | (c->c_keytype == KT_ED25519 ? "ssh-ed25519" : |
258 | "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521")); | 273 | "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521")); |
259 | if ((r = kex_setup(active_state, myproposal)) < 0) | 274 | if ((r = kex_setup(c->c_ssh, myproposal)) != 0) { |
260 | fatal("%s: kex_setup: %s", __func__, ssh_err(r)); | 275 | free(c->c_ssh); |
261 | c->c_kex = active_state->kex; | 276 | fprintf(stderr, "kex_setup: %s\n", ssh_err(r)); |
262 | #ifdef WITH_OPENSSL | ||
263 | c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; | ||
264 | c->c_kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; | ||
265 | c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; | ||
266 | c->c_kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; | ||
267 | c->c_kex->kex[KEX_ECDH_SHA2] = kexecdh_client; | ||
268 | #endif | ||
269 | c->c_kex->kex[KEX_C25519_SHA256] = kexc25519_client; | ||
270 | c->c_kex->verify_host_key = hostjump; | ||
271 | |||
272 | if (!(j = setjmp(kexjmp))) { | ||
273 | nonfatal_fatal = 1; | ||
274 | dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, active_state); | ||
275 | fprintf(stderr, "Impossible! dispatch_run() returned!\n"); | ||
276 | exit(1); | 277 | exit(1); |
277 | } | 278 | } |
278 | nonfatal_fatal = 0; | 279 | #ifdef WITH_OPENSSL |
279 | free(c->c_kex); | 280 | c->c_ssh->kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; |
280 | c->c_kex = NULL; | 281 | c->c_ssh->kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; |
281 | packet_close(); | 282 | c->c_ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; |
282 | 283 | c->c_ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; | |
283 | return j < 0? NULL : kexjmp_key; | 284 | c->c_ssh->kex->kex[KEX_ECDH_SHA2] = kexecdh_client; |
285 | #endif | ||
286 | c->c_ssh->kex->kex[KEX_C25519_SHA256] = kexc25519_client; | ||
287 | ssh_set_verify_host_key_callback(c->c_ssh, key_print_wrapper); | ||
288 | /* | ||
289 | * do the key-exchange until an error occurs or until | ||
290 | * the key_print_wrapper() callback sets c_done. | ||
291 | */ | ||
292 | ssh_dispatch_run(c->c_ssh, DISPATCH_BLOCK, &c->c_done, c->c_ssh); | ||
284 | } | 293 | } |
285 | 294 | ||
286 | static void | 295 | static void |
287 | keyprint(con *c, Key *key) | 296 | keyprint(con *c, struct sshkey *key) |
288 | { | 297 | { |
289 | char *host = c->c_output_name ? c->c_output_name : c->c_name; | 298 | char *host = c->c_output_name ? c->c_output_name : c->c_name; |
290 | 299 | ||
@@ -294,7 +303,7 @@ keyprint(con *c, Key *key) | |||
294 | fatal("host_hash failed"); | 303 | fatal("host_hash failed"); |
295 | 304 | ||
296 | fprintf(stdout, "%s ", host); | 305 | fprintf(stdout, "%s ", host); |
297 | key_write(key, stdout); | 306 | sshkey_write(key, stdout); |
298 | fputs("\n", stdout); | 307 | fputs("\n", stdout); |
299 | } | 308 | } |
300 | 309 | ||
@@ -382,6 +391,11 @@ confree(int s) | |||
382 | free(fdcon[s].c_data); | 391 | free(fdcon[s].c_data); |
383 | fdcon[s].c_status = CS_UNUSED; | 392 | fdcon[s].c_status = CS_UNUSED; |
384 | fdcon[s].c_keytype = 0; | 393 | fdcon[s].c_keytype = 0; |
394 | if (fdcon[s].c_ssh) { | ||
395 | ssh_packet_close(fdcon[s].c_ssh); | ||
396 | free(fdcon[s].c_ssh); | ||
397 | fdcon[s].c_ssh = NULL; | ||
398 | } | ||
385 | TAILQ_REMOVE(&tq, &fdcon[s], c_link); | 399 | TAILQ_REMOVE(&tq, &fdcon[s], c_link); |
386 | FD_CLR(s, read_wait); | 400 | FD_CLR(s, read_wait); |
387 | ncon--; | 401 | ncon--; |
@@ -449,11 +463,13 @@ congreet(int s) | |||
449 | return; | 463 | return; |
450 | } | 464 | } |
451 | *cp = '\0'; | 465 | *cp = '\0'; |
466 | c->c_ssh = ssh_packet_set_connection(NULL, s, s); | ||
467 | ssh_set_app_data(c->c_ssh, c); /* back link */ | ||
452 | if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", | 468 | if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", |
453 | &remote_major, &remote_minor, remote_version) == 3) | 469 | &remote_major, &remote_minor, remote_version) == 3) |
454 | compat_datafellows(remote_version); | 470 | c->c_ssh->compat = compat_datafellows(remote_version); |
455 | else | 471 | else |
456 | datafellows = 0; | 472 | c->c_ssh->compat = 0; |
457 | if (c->c_keytype != KT_RSA1) { | 473 | if (c->c_keytype != KT_RSA1) { |
458 | if (!ssh2_capable(remote_major, remote_minor)) { | 474 | if (!ssh2_capable(remote_major, remote_minor)) { |
459 | debug("%s doesn't support ssh2", c->c_name); | 475 | debug("%s doesn't support ssh2", c->c_name); |
@@ -480,7 +496,7 @@ congreet(int s) | |||
480 | return; | 496 | return; |
481 | } | 497 | } |
482 | if (c->c_keytype != KT_RSA1) { | 498 | if (c->c_keytype != KT_RSA1) { |
483 | keyprint(c, keygrab_ssh2(c)); | 499 | keygrab_ssh2(c); |
484 | confree(s); | 500 | confree(s); |
485 | return; | 501 | return; |
486 | } | 502 | } |
@@ -606,10 +622,7 @@ fatal(const char *fmt,...) | |||
606 | va_start(args, fmt); | 622 | va_start(args, fmt); |
607 | do_log(SYSLOG_LEVEL_FATAL, fmt, args); | 623 | do_log(SYSLOG_LEVEL_FATAL, fmt, args); |
608 | va_end(args); | 624 | va_end(args); |
609 | if (nonfatal_fatal) | 625 | exit(255); |
610 | longjmp(kexjmp, -1); | ||
611 | else | ||
612 | exit(255); | ||
613 | } | 626 | } |
614 | 627 | ||
615 | static void | 628 | static void |
@@ -682,7 +695,7 @@ main(int argc, char **argv) | |||
682 | get_keytypes = 0; | 695 | get_keytypes = 0; |
683 | tname = strtok(optarg, ","); | 696 | tname = strtok(optarg, ","); |
684 | while (tname) { | 697 | while (tname) { |
685 | int type = key_type_from_name(tname); | 698 | int type = sshkey_type_from_name(tname); |
686 | switch (type) { | 699 | switch (type) { |
687 | case KEY_RSA1: | 700 | case KEY_RSA1: |
688 | get_keytypes |= KT_RSA1; | 701 | get_keytypes |= KT_RSA1; |