diff options
-rw-r--r-- | ChangeLog | 23 | ||||
-rw-r--r-- | key.c | 105 | ||||
-rw-r--r-- | key.h | 5 | ||||
-rw-r--r-- | readconf.c | 20 | ||||
-rw-r--r-- | readconf.h | 6 | ||||
-rw-r--r-- | ssh-keygen.1 | 9 | ||||
-rw-r--r-- | ssh-keygen.c | 21 | ||||
-rw-r--r-- | ssh_config.5 | 8 | ||||
-rw-r--r-- | sshconnect.c | 26 |
9 files changed, 199 insertions, 24 deletions
@@ -3,6 +3,27 @@ | |||
3 | - jmc@cvs.openbsd.org 2008/06/11 07:30:37 | 3 | - jmc@cvs.openbsd.org 2008/06/11 07:30:37 |
4 | [sshd.8] | 4 | [sshd.8] |
5 | kill trailing whitespace; | 5 | kill trailing whitespace; |
6 | - grunk@cvs.openbsd.org 2008/06/11 21:01:35 | ||
7 | [ssh_config.5 key.h readconf.c readconf.h ssh-keygen.1 ssh-keygen.c key.c | ||
8 | sshconnect.c] | ||
9 | Introduce SSH Fingerprint ASCII Visualization, a technique inspired by the | ||
10 | graphical hash visualization schemes known as "random art", and by | ||
11 | Dan Kaminsky's musings on the subject during a BlackOp talk at the | ||
12 | 23C3 in Berlin. | ||
13 | Scientific publication (original paper): | ||
14 | "Hash Visualization: a New Technique to improve Real-World Security", | ||
15 | Perrig A. and Song D., 1999, International Workshop on Cryptographic | ||
16 | Techniques and E-Commerce (CrypTEC '99) | ||
17 | http://sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf | ||
18 | The algorithm used here is a worm crawling over a discrete plane, | ||
19 | leaving a trace (augmenting the field) everywhere it goes. | ||
20 | Movement is taken from dgst_raw 2bit-wise. Bumping into walls | ||
21 | makes the respective movement vector be ignored for this turn, | ||
22 | thus switching to the other color of the chessboard. | ||
23 | Graphs are not unambiguous for now, because circles in graphs can be | ||
24 | walked in either direction. | ||
25 | discussions with several people, | ||
26 | help, corrections and ok markus@ djm@ | ||
6 | 27 | ||
7 | 20080611 | 28 | 20080611 |
8 | - (djm) [channels.c configure.ac] | 29 | - (djm) [channels.c configure.ac] |
@@ -4165,4 +4186,4 @@ | |||
4165 | OpenServer 6 and add osr5bigcrypt support so when someone migrates | 4186 | OpenServer 6 and add osr5bigcrypt support so when someone migrates |
4166 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ | 4187 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ |
4167 | 4188 | ||
4168 | $Id: ChangeLog,v 1.4968 2008/06/12 18:32:00 dtucker Exp $ | 4189 | $Id: ChangeLog,v 1.4969 2008/06/12 18:40:35 dtucker Exp $ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: key.c,v 1.69 2007/07/12 05:48:05 ray Exp $ */ | 1 | /* $OpenBSD: key.c,v 1.70 2008/06/11 21:01:35 grunk Exp $ */ |
2 | /* | 2 | /* |
3 | * read_bignum(): | 3 | * read_bignum(): |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -35,6 +35,7 @@ | |||
35 | 35 | ||
36 | #include "includes.h" | 36 | #include "includes.h" |
37 | 37 | ||
38 | #include <sys/param.h> | ||
38 | #include <sys/types.h> | 39 | #include <sys/types.h> |
39 | 40 | ||
40 | #include <openssl/evp.h> | 41 | #include <openssl/evp.h> |
@@ -295,6 +296,105 @@ key_fingerprint_bubblebabble(u_char *dgst_raw, u_int dgst_raw_len) | |||
295 | return retval; | 296 | return retval; |
296 | } | 297 | } |
297 | 298 | ||
299 | /* | ||
300 | * Draw an ASCII-Art representing the fingerprint so human brain can | ||
301 | * profit from its built-in pattern recognition ability. | ||
302 | * This technique is called "random art" and can be found in some | ||
303 | * scientific publications like this original paper: | ||
304 | * | ||
305 | * "Hash Visualization: a New Technique to improve Real-World Security", | ||
306 | * Perrig A. and Song D., 1999, International Workshop on Cryptographic | ||
307 | * Techniques and E-Commerce (CrypTEC '99) | ||
308 | * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf | ||
309 | * | ||
310 | * The subject came up in a talk by Dan Kaminsky, too. | ||
311 | * | ||
312 | * If you see the picture is different, the key is different. | ||
313 | * If the picture looks the same, you still know nothing. | ||
314 | * | ||
315 | * The algorithm used here is a worm crawling over a discrete plane, | ||
316 | * leaving a trace (augmenting the field) everywhere it goes. | ||
317 | * Movement is taken from dgst_raw 2bit-wise. Bumping into walls | ||
318 | * makes the respective movement vector be ignored for this turn. | ||
319 | * Graphs are not unambiguous, because circles in graphs can be | ||
320 | * walked in either direction. | ||
321 | */ | ||
322 | #define FLDSIZE_Y 8 | ||
323 | #define FLDSIZE_X FLDSIZE_Y * 2 | ||
324 | static char * | ||
325 | key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len) | ||
326 | { | ||
327 | /* | ||
328 | * Chars to be used after each other every time the worm | ||
329 | * intersects with itself. Matter of taste. | ||
330 | */ | ||
331 | char *augmentation_string = " .o+=*BOX@%&#/^"; | ||
332 | char *retval, *p; | ||
333 | char field[FLDSIZE_X][FLDSIZE_Y]; | ||
334 | u_int i, b; | ||
335 | int x, y; | ||
336 | |||
337 | retval = xcalloc(1, (FLDSIZE_X + 3) * (FLDSIZE_Y + 2)); | ||
338 | |||
339 | /* initialize field */ | ||
340 | memset(field, ' ', FLDSIZE_X * FLDSIZE_Y * sizeof(char)); | ||
341 | x = FLDSIZE_X / 2; | ||
342 | y = FLDSIZE_Y / 2; | ||
343 | field[x][y] = '.'; | ||
344 | |||
345 | /* process raw key */ | ||
346 | for (i = 0; i < dgst_raw_len; i++) { | ||
347 | int input; | ||
348 | /* each byte conveys four 2-bit move commands */ | ||
349 | input = dgst_raw[i]; | ||
350 | for (b = 0; b < 4; b++) { | ||
351 | /* evaluate 2 bit, rest is shifted later */ | ||
352 | x += (input & 0x1) ? 1 : -1; | ||
353 | y += (input & 0x2) ? 1 : -1; | ||
354 | |||
355 | /* assure we are still in bounds */ | ||
356 | x = MAX(x, 0); | ||
357 | y = MAX(y, 0); | ||
358 | x = MIN(x, FLDSIZE_X - 1); | ||
359 | y = MIN(y, FLDSIZE_Y - 1); | ||
360 | |||
361 | /* augment the field */ | ||
362 | p = strchr(augmentation_string, field[x][y]); | ||
363 | if (*++p != '\0') | ||
364 | field[x][y] = *p; | ||
365 | |||
366 | input = input >> 2; | ||
367 | } | ||
368 | } | ||
369 | |||
370 | /* fill in retval */ | ||
371 | p = retval; | ||
372 | |||
373 | /* output upper border */ | ||
374 | *p++ = '+'; | ||
375 | for (i = 0; i < FLDSIZE_X; i++) | ||
376 | *p++ = '-'; | ||
377 | *p++ = '+'; | ||
378 | *p++ = '\n'; | ||
379 | |||
380 | /* output content */ | ||
381 | for (y = 0; y < FLDSIZE_Y; y++) { | ||
382 | *p++ = '|'; | ||
383 | for (x = 0; x < FLDSIZE_X; x++) | ||
384 | *p++ = field[x][y]; | ||
385 | *p++ = '|'; | ||
386 | *p++ = '\n'; | ||
387 | } | ||
388 | |||
389 | /* output lower border */ | ||
390 | *p++ = '+'; | ||
391 | for (i = 0; i < FLDSIZE_X; i++) | ||
392 | *p++ = '-'; | ||
393 | *p++ = '+'; | ||
394 | |||
395 | return retval; | ||
396 | } | ||
397 | |||
298 | char * | 398 | char * |
299 | key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) | 399 | key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) |
300 | { | 400 | { |
@@ -312,6 +412,9 @@ key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) | |||
312 | case SSH_FP_BUBBLEBABBLE: | 412 | case SSH_FP_BUBBLEBABBLE: |
313 | retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len); | 413 | retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len); |
314 | break; | 414 | break; |
415 | case SSH_FP_RANDOMART: | ||
416 | retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len); | ||
417 | break; | ||
315 | default: | 418 | default: |
316 | fatal("key_fingerprint_ex: bad digest representation %d", | 419 | fatal("key_fingerprint_ex: bad digest representation %d", |
317 | dgst_rep); | 420 | dgst_rep); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: key.h,v 1.26 2006/08/03 03:34:42 deraadt Exp $ */ | 1 | /* $OpenBSD: key.h,v 1.27 2008/06/11 21:01:35 grunk Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
@@ -42,7 +42,8 @@ enum fp_type { | |||
42 | }; | 42 | }; |
43 | enum fp_rep { | 43 | enum fp_rep { |
44 | SSH_FP_HEX, | 44 | SSH_FP_HEX, |
45 | SSH_FP_BUBBLEBABBLE | 45 | SSH_FP_BUBBLEBABBLE, |
46 | SSH_FP_RANDOMART | ||
46 | }; | 47 | }; |
47 | 48 | ||
48 | /* key is stored in external hardware */ | 49 | /* key is stored in external hardware */ |
diff --git a/readconf.c b/readconf.c index 3ddb4d392..1d61145c4 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.c,v 1.165 2008/01/19 23:09:49 djm Exp $ */ | 1 | /* $OpenBSD: readconf.c,v 1.166 2008/06/11 21:01:35 grunk Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -452,7 +452,23 @@ parse_flag: | |||
452 | 452 | ||
453 | case oCheckHostIP: | 453 | case oCheckHostIP: |
454 | intptr = &options->check_host_ip; | 454 | intptr = &options->check_host_ip; |
455 | goto parse_flag; | 455 | arg = strdelim(&s); |
456 | if (!arg || *arg == '\0') | ||
457 | fatal("%.200s line %d: Missing CheckHostIP argument.", | ||
458 | filename, linenum); | ||
459 | value = 0; /* To avoid compiler warning... */ | ||
460 | if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) | ||
461 | value = SSHCTL_CHECKHOSTIP_YES; | ||
462 | else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) | ||
463 | value = SSHCTL_CHECKHOSTIP_NO; | ||
464 | else if (strcmp(arg, "fingerprint") == 0) | ||
465 | value = SSHCTL_CHECKHOSTIP_FPR; | ||
466 | else | ||
467 | fatal("%.200s line %d: Bad CheckHostIP argument.", | ||
468 | filename, linenum); | ||
469 | if (*activep && *intptr == -1) | ||
470 | *intptr = value; | ||
471 | break; | ||
456 | 472 | ||
457 | case oVerifyHostKeyDNS: | 473 | case oVerifyHostKeyDNS: |
458 | intptr = &options->verify_host_key_dns; | 474 | intptr = &options->verify_host_key_dns; |
diff --git a/readconf.h b/readconf.h index 6257f4b2f..5c16a0ba6 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.h,v 1.72 2008/01/19 23:09:49 djm Exp $ */ | 1 | /* $OpenBSD: readconf.h,v 1.73 2008/06/11 21:01:35 grunk Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -123,6 +123,10 @@ typedef struct { | |||
123 | 123 | ||
124 | } Options; | 124 | } Options; |
125 | 125 | ||
126 | #define SSHCTL_CHECKHOSTIP_NO 0 | ||
127 | #define SSHCTL_CHECKHOSTIP_YES 1 | ||
128 | #define SSHCTL_CHECKHOSTIP_FPR 2 | ||
129 | |||
126 | #define SSHCTL_MASTER_NO 0 | 130 | #define SSHCTL_MASTER_NO 0 |
127 | #define SSHCTL_MASTER_YES 1 | 131 | #define SSHCTL_MASTER_YES 1 |
128 | #define SSHCTL_MASTER_AUTO 2 | 132 | #define SSHCTL_MASTER_AUTO 2 |
diff --git a/ssh-keygen.1 b/ssh-keygen.1 index 877935053..36249b288 100644 --- a/ssh-keygen.1 +++ b/ssh-keygen.1 | |||
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: ssh-keygen.1,v 1.75 2007/05/31 19:20:16 jmc Exp $ | 1 | .\" $OpenBSD: ssh-keygen.1,v 1.76 2008/06/11 21:01:35 grunk Exp $ |
2 | .\" | 2 | .\" |
3 | .\" -*- nroff -*- | 3 | .\" -*- nroff -*- |
4 | .\" | 4 | .\" |
@@ -37,7 +37,7 @@ | |||
37 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 37 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
38 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 38 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
39 | .\" | 39 | .\" |
40 | .Dd $Mdocdate: May 31 2007 $ | 40 | .Dd $Mdocdate: June 11 2008 $ |
41 | .Dt SSH-KEYGEN 1 | 41 | .Dt SSH-KEYGEN 1 |
42 | .Os | 42 | .Os |
43 | .Sh NAME | 43 | .Sh NAME |
@@ -257,11 +257,12 @@ RFC 4716 SSH Public Key File Format. | |||
257 | This option allows importing keys from several commercial | 257 | This option allows importing keys from several commercial |
258 | SSH implementations. | 258 | SSH implementations. |
259 | .It Fl l | 259 | .It Fl l |
260 | Show fingerprint of specified public key file. | 260 | Show fingerprint and ASCII art representation of specified public key file. |
261 | Private RSA1 keys are also supported. | 261 | Private RSA1 keys are also supported. |
262 | For RSA and DSA keys | 262 | For RSA and DSA keys |
263 | .Nm | 263 | .Nm |
264 | tries to find the matching public key file and prints its fingerprint. | 264 | tries to find the matching public key file and prints its fingerprint |
265 | and representation. | ||
265 | .It Fl M Ar memory | 266 | .It Fl M Ar memory |
266 | Specify the amount of memory to use (in megabytes) when generating | 267 | Specify the amount of memory to use (in megabytes) when generating |
267 | candidate moduli for DH-GEX. | 268 | candidate moduli for DH-GEX. |
diff --git a/ssh-keygen.c b/ssh-keygen.c index a03c6575d..c22e814da 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.166 2008/05/19 15:46:31 djm Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.167 2008/06/11 21:01:35 grunk Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -504,7 +504,7 @@ do_fingerprint(struct passwd *pw) | |||
504 | { | 504 | { |
505 | FILE *f; | 505 | FILE *f; |
506 | Key *public; | 506 | Key *public; |
507 | char *comment = NULL, *cp, *ep, line[16*1024], *fp; | 507 | char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra; |
508 | int i, skip = 0, num = 0, invalid = 1; | 508 | int i, skip = 0, num = 0, invalid = 1; |
509 | enum fp_rep rep; | 509 | enum fp_rep rep; |
510 | enum fp_type fptype; | 510 | enum fp_type fptype; |
@@ -522,9 +522,12 @@ do_fingerprint(struct passwd *pw) | |||
522 | public = key_load_public(identity_file, &comment); | 522 | public = key_load_public(identity_file, &comment); |
523 | if (public != NULL) { | 523 | if (public != NULL) { |
524 | fp = key_fingerprint(public, fptype, rep); | 524 | fp = key_fingerprint(public, fptype, rep); |
525 | ra = key_fingerprint(public, fptype, rep); | ||
525 | printf("%u %s %s\n", key_size(public), fp, comment); | 526 | printf("%u %s %s\n", key_size(public), fp, comment); |
527 | verbose("%s\n", ra); | ||
526 | key_free(public); | 528 | key_free(public); |
527 | xfree(comment); | 529 | xfree(comment); |
530 | xfree(ra); | ||
528 | xfree(fp); | 531 | xfree(fp); |
529 | exit(0); | 532 | exit(0); |
530 | } | 533 | } |
@@ -582,8 +585,11 @@ do_fingerprint(struct passwd *pw) | |||
582 | } | 585 | } |
583 | comment = *cp ? cp : comment; | 586 | comment = *cp ? cp : comment; |
584 | fp = key_fingerprint(public, fptype, rep); | 587 | fp = key_fingerprint(public, fptype, rep); |
588 | ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); | ||
585 | printf("%u %s %s\n", key_size(public), fp, | 589 | printf("%u %s %s\n", key_size(public), fp, |
586 | comment ? comment : "no comment"); | 590 | comment ? comment : "no comment"); |
591 | verbose("%s\n", ra); | ||
592 | xfree(ra); | ||
587 | xfree(fp); | 593 | xfree(fp); |
588 | key_free(public); | 594 | key_free(public); |
589 | invalid = 0; | 595 | invalid = 0; |
@@ -603,12 +609,14 @@ print_host(FILE *f, const char *name, Key *public, int hash) | |||
603 | if (print_fingerprint) { | 609 | if (print_fingerprint) { |
604 | enum fp_rep rep; | 610 | enum fp_rep rep; |
605 | enum fp_type fptype; | 611 | enum fp_type fptype; |
606 | char *fp; | 612 | char *fp, *ra; |
607 | 613 | ||
608 | fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; | 614 | fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; |
609 | rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; | 615 | rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; |
610 | fp = key_fingerprint(public, fptype, rep); | 616 | fp = key_fingerprint(public, fptype, rep); |
611 | printf("%u %s %s\n", key_size(public), fp, name); | 617 | ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); |
618 | printf("%u %s %s\n%s\n", key_size(public), fp, name, ra); | ||
619 | xfree(ra); | ||
612 | xfree(fp); | 620 | xfree(fp); |
613 | } else { | 621 | } else { |
614 | if (hash && (name = host_hash(name, NULL, 0)) == NULL) | 622 | if (hash && (name = host_hash(name, NULL, 0)) == NULL) |
@@ -1451,10 +1459,15 @@ passphrase_again: | |||
1451 | 1459 | ||
1452 | if (!quiet) { | 1460 | if (!quiet) { |
1453 | char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); | 1461 | char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); |
1462 | char *ra = key_fingerprint(public, SSH_FP_MD5, | ||
1463 | SSH_FP_RANDOMART); | ||
1454 | printf("Your public key has been saved in %s.\n", | 1464 | printf("Your public key has been saved in %s.\n", |
1455 | identity_file); | 1465 | identity_file); |
1456 | printf("The key fingerprint is:\n"); | 1466 | printf("The key fingerprint is:\n"); |
1457 | printf("%s %s\n", fp, comment); | 1467 | printf("%s %s\n", fp, comment); |
1468 | printf("The key's randomart image is:\n"); | ||
1469 | printf("%s\n", ra); | ||
1470 | xfree(ra); | ||
1458 | xfree(fp); | 1471 | xfree(fp); |
1459 | } | 1472 | } |
1460 | 1473 | ||
diff --git a/ssh_config.5 b/ssh_config.5 index d6f3fbf80..28ac724c8 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -34,8 +34,8 @@ | |||
34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | .\" | 36 | .\" |
37 | .\" $OpenBSD: ssh_config.5,v 1.106 2008/06/10 18:21:24 dtucker Exp $ | 37 | .\" $OpenBSD: ssh_config.5,v 1.107 2008/06/11 21:01:35 grunk Exp $ |
38 | .Dd $Mdocdate: June 10 2008 $ | 38 | .Dd $Mdocdate: June 11 2008 $ |
39 | .Dt SSH_CONFIG 5 | 39 | .Dt SSH_CONFIG 5 |
40 | .Os | 40 | .Os |
41 | .Sh NAME | 41 | .Sh NAME |
@@ -161,6 +161,10 @@ will additionally check the host IP address in the | |||
161 | file. | 161 | file. |
162 | This allows ssh to detect if a host key changed due to DNS spoofing. | 162 | This allows ssh to detect if a host key changed due to DNS spoofing. |
163 | If the option is set to | 163 | If the option is set to |
164 | .Dq fingerprint , | ||
165 | not only the host IP address will be checked, but also an ASCII art | ||
166 | representation of the key will be printed. | ||
167 | If the option is set to | ||
164 | .Dq no , | 168 | .Dq no , |
165 | the check will not be executed. | 169 | the check will not be executed. |
166 | The default is | 170 | The default is |
diff --git a/sshconnect.c b/sshconnect.c index a604c9724..151299614 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect.c,v 1.203 2007/12/27 14:22:08 dtucker Exp $ */ | 1 | /* $OpenBSD: sshconnect.c,v 1.204 2008/06/11 21:01:35 grunk Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -602,7 +602,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
602 | Key *file_key; | 602 | Key *file_key; |
603 | const char *type = key_type(host_key); | 603 | const char *type = key_type(host_key); |
604 | char *ip = NULL, *host = NULL; | 604 | char *ip = NULL, *host = NULL; |
605 | char hostline[1000], *hostp, *fp; | 605 | char hostline[1000], *hostp, *fp, *ra; |
606 | HostStatus host_status; | 606 | HostStatus host_status; |
607 | HostStatus ip_status; | 607 | HostStatus ip_status; |
608 | int r, local = 0, host_ip_differ = 0; | 608 | int r, local = 0, host_ip_differ = 0; |
@@ -740,6 +740,13 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
740 | logit("Warning: Permanently added the %s host " | 740 | logit("Warning: Permanently added the %s host " |
741 | "key for IP address '%.128s' to the list " | 741 | "key for IP address '%.128s' to the list " |
742 | "of known hosts.", type, ip); | 742 | "of known hosts.", type, ip); |
743 | } else if (options.check_host_ip == SSHCTL_CHECKHOSTIP_FPR) { | ||
744 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | ||
745 | ra = key_fingerprint(host_key, SSH_FP_MD5, | ||
746 | SSH_FP_RANDOMART); | ||
747 | logit("Host key fingerprint is %s\n%s\n", fp, ra); | ||
748 | xfree(ra); | ||
749 | xfree(fp); | ||
743 | } | 750 | } |
744 | break; | 751 | break; |
745 | case HOST_NEW: | 752 | case HOST_NEW: |
@@ -775,6 +782,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
775 | snprintf(msg1, sizeof(msg1), "."); | 782 | snprintf(msg1, sizeof(msg1), "."); |
776 | /* The default */ | 783 | /* The default */ |
777 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | 784 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); |
785 | ra = key_fingerprint(host_key, SSH_FP_MD5, | ||
786 | SSH_FP_RANDOMART); | ||
778 | msg2[0] = '\0'; | 787 | msg2[0] = '\0'; |
779 | if (options.verify_host_key_dns) { | 788 | if (options.verify_host_key_dns) { |
780 | if (matching_host_key_dns) | 789 | if (matching_host_key_dns) |
@@ -789,10 +798,11 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | |||
789 | snprintf(msg, sizeof(msg), | 798 | snprintf(msg, sizeof(msg), |
790 | "The authenticity of host '%.200s (%s)' can't be " | 799 | "The authenticity of host '%.200s (%s)' can't be " |
791 | "established%s\n" | 800 | "established%s\n" |
792 | "%s key fingerprint is %s.\n%s" | 801 | "%s key fingerprint is %s.\n%s\n%s" |
793 | "Are you sure you want to continue connecting " | 802 | "Are you sure you want to continue connecting " |
794 | "(yes/no)? ", | 803 | "(yes/no)? ", |
795 | host, ip, msg1, type, fp, msg2); | 804 | host, ip, msg1, type, fp, ra, msg2); |
805 | xfree(ra); | ||
796 | xfree(fp); | 806 | xfree(fp); |
797 | if (!confirm(msg)) | 807 | if (!confirm(msg)) |
798 | goto fail; | 808 | goto fail; |
@@ -1063,18 +1073,20 @@ static int | |||
1063 | show_key_from_file(const char *file, const char *host, int keytype) | 1073 | show_key_from_file(const char *file, const char *host, int keytype) |
1064 | { | 1074 | { |
1065 | Key *found; | 1075 | Key *found; |
1066 | char *fp; | 1076 | char *fp, *ra; |
1067 | int line, ret; | 1077 | int line, ret; |
1068 | 1078 | ||
1069 | found = key_new(keytype); | 1079 | found = key_new(keytype); |
1070 | if ((ret = lookup_key_in_hostfile_by_type(file, host, | 1080 | if ((ret = lookup_key_in_hostfile_by_type(file, host, |
1071 | keytype, found, &line))) { | 1081 | keytype, found, &line))) { |
1072 | fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); | 1082 | fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); |
1083 | ra = key_fingerprint(found, SSH_FP_MD5, SSH_FP_RANDOMART); | ||
1073 | logit("WARNING: %s key found for host %s\n" | 1084 | logit("WARNING: %s key found for host %s\n" |
1074 | "in %s:%d\n" | 1085 | "in %s:%d\n" |
1075 | "%s key fingerprint %s.", | 1086 | "%s key fingerprint %s.\n%s\n", |
1076 | key_type(found), host, file, line, | 1087 | key_type(found), host, file, line, |
1077 | key_type(found), fp); | 1088 | key_type(found), fp, ra); |
1089 | xfree(ra); | ||
1078 | xfree(fp); | 1090 | xfree(fp); |
1079 | } | 1091 | } |
1080 | key_free(found); | 1092 | key_free(found); |