X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/c1cb7bae1a56520c8bc58c1753faddacb16ac646..HEAD:/key.c diff --git a/key.c b/key.c index 8e6ccc2b..5aea416b 100644 --- a/key.c +++ b/key.c @@ -1,4 +1,4 @@ -/* $OpenBSD: key.c,v 1.64 2006/03/25 13:17:02 djm Exp $ */ +/* $OpenBSD: key.c,v 1.82 2010/01/13 01:10:56 dtucker Exp $ */ /* * read_bignum(): * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -11,6 +11,7 @@ * * * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2008 Alexander von Gernler. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,16 +33,24 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #include "includes.h" +#include +#include + #include +#include + +#include +#include +#include #include "xmalloc.h" #include "key.h" #include "rsa.h" #include "uuencode.h" #include "buffer.h" -#include "bufaux.h" #include "log.h" Key * @@ -164,9 +173,8 @@ key_equal(const Key *a, const Key *b) BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; default: fatal("key_equal: bad key type %d", a->type); - break; } - return 0; + /* NOTREACHED */ } u_char* @@ -290,6 +298,115 @@ key_fingerprint_bubblebabble(u_char *dgst_raw, u_int dgst_raw_len) return retval; } +/* + * Draw an ASCII-Art representing the fingerprint so human brain can + * profit from its built-in pattern recognition ability. + * This technique is called "random art" and can be found in some + * scientific publications like this original paper: + * + * "Hash Visualization: a New Technique to improve Real-World Security", + * Perrig A. and Song D., 1999, International Workshop on Cryptographic + * Techniques and E-Commerce (CrypTEC '99) + * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf + * + * The subject came up in a talk by Dan Kaminsky, too. + * + * If you see the picture is different, the key is different. + * If the picture looks the same, you still know nothing. + * + * The algorithm used here is a worm crawling over a discrete plane, + * leaving a trace (augmenting the field) everywhere it goes. + * Movement is taken from dgst_raw 2bit-wise. Bumping into walls + * makes the respective movement vector be ignored for this turn. + * Graphs are not unambiguous, because circles in graphs can be + * walked in either direction. + */ + +/* + * Field sizes for the random art. Have to be odd, so the starting point + * can be in the exact middle of the picture, and FLDBASE should be >=8 . + * Else pictures would be too dense, and drawing the frame would + * fail, too, because the key type would not fit in anymore. + */ +#define FLDBASE 8 +#define FLDSIZE_Y (FLDBASE + 1) +#define FLDSIZE_X (FLDBASE * 2 + 1) +static char * +key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k) +{ + /* + * Chars to be used after each other every time the worm + * intersects with itself. Matter of taste. + */ + char *augmentation_string = " .o+=*BOX@%&#/^SE"; + char *retval, *p; + u_char field[FLDSIZE_X][FLDSIZE_Y]; + u_int i, b; + int x, y; + size_t len = strlen(augmentation_string) - 1; + + retval = xcalloc(1, (FLDSIZE_X + 3) * (FLDSIZE_Y + 2)); + + /* initialize field */ + memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char)); + x = FLDSIZE_X / 2; + y = FLDSIZE_Y / 2; + + /* process raw key */ + for (i = 0; i < dgst_raw_len; i++) { + int input; + /* each byte conveys four 2-bit move commands */ + input = dgst_raw[i]; + for (b = 0; b < 4; b++) { + /* evaluate 2 bit, rest is shifted later */ + x += (input & 0x1) ? 1 : -1; + y += (input & 0x2) ? 1 : -1; + + /* assure we are still in bounds */ + x = MAX(x, 0); + y = MAX(y, 0); + x = MIN(x, FLDSIZE_X - 1); + y = MIN(y, FLDSIZE_Y - 1); + + /* augment the field */ + if (field[x][y] < len - 2) + field[x][y]++; + input = input >> 2; + } + } + + /* mark starting point and end point*/ + field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1; + field[x][y] = len; + + /* fill in retval */ + snprintf(retval, FLDSIZE_X, "+--[%4s %4u]", key_type(k), key_size(k)); + p = strchr(retval, '\0'); + + /* output upper border */ + for (i = p - retval - 1; i < FLDSIZE_X; i++) + *p++ = '-'; + *p++ = '+'; + *p++ = '\n'; + + /* output content */ + for (y = 0; y < FLDSIZE_Y; y++) { + *p++ = '|'; + for (x = 0; x < FLDSIZE_X; x++) + *p++ = augmentation_string[MIN(field[x][y], len)]; + *p++ = '|'; + *p++ = '\n'; + } + + /* output lower border */ + *p++ = '+'; + for (i = 0; i < FLDSIZE_X; i++) + *p++ = '-'; + *p++ = '+'; + + return retval; +} + char * key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) { @@ -307,8 +424,11 @@ key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) case SSH_FP_BUBBLEBABBLE: retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len); break; + case SSH_FP_RANDOMART: + retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len, k); + break; default: - fatal("key_fingerprint_ex: bad digest representation %d", + fatal("key_fingerprint: bad digest representation %d", dgst_rep); break; } @@ -402,6 +522,12 @@ key_read(Key *ret, char **cpp) return -1; if (!read_bignum(cpp, ret->rsa->n)) return -1; + /* validate the claimed number of bits */ + if ((u_int)BN_num_bits(ret->rsa->n) != bits) { + verbose("key_read: claimed key size %d does not match " + "actual %d", bits, BN_num_bits(ret->rsa->n)); + return -1; + } success = 1; break; case KEY_UNSPEC: @@ -565,7 +691,7 @@ rsa_generate_private_key(u_int bits) { RSA *private; - private = RSA_generate_key(bits, 35, NULL, NULL); + private = RSA_generate_key(bits, RSA_F4, NULL, NULL); if (private == NULL) fatal("rsa_generate_private_key: key generation failed."); return private; @@ -611,16 +737,18 @@ key_from_private(const Key *k) switch (k->type) { case KEY_DSA: n = key_new(k->type); - BN_copy(n->dsa->p, k->dsa->p); - BN_copy(n->dsa->q, k->dsa->q); - BN_copy(n->dsa->g, k->dsa->g); - BN_copy(n->dsa->pub_key, k->dsa->pub_key); + if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) || + (BN_copy(n->dsa->q, k->dsa->q) == NULL) || + (BN_copy(n->dsa->g, k->dsa->g) == NULL) || + (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL)) + fatal("key_from_private: BN_copy failed"); break; case KEY_RSA: case KEY_RSA1: n = key_new(k->type); - BN_copy(n->rsa->n, k->rsa->n); - BN_copy(n->rsa->e, k->rsa->e); + if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) || + (BN_copy(n->rsa->e, k->rsa->e) == NULL)) + fatal("key_from_private: BN_copy failed"); break; default: fatal("key_from_private: unknown type %d", k->type);