X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/e557416818242c2e8b14ec03d321740fd83619e4..3709bfe9981af43e3cd491c37d300b57e5b26d50:/sshdss.c diff --git a/sshdss.c b/sshdss.c index c651140e..cf7fc3f7 100644 --- a/sshdss.c +++ b/sshdss.c @@ -1,5 +1,289 @@ +#include +#include + #include "ssh.h" -struct ssh_hostkey ssh_dss = { - "ssh-dss" +#define GET_32BIT(cp) \ + (((unsigned long)(unsigned char)(cp)[0] << 24) | \ + ((unsigned long)(unsigned char)(cp)[1] << 16) | \ + ((unsigned long)(unsigned char)(cp)[2] << 8) | \ + ((unsigned long)(unsigned char)(cp)[3])) + +#define PUT_32BIT(cp, value) { \ + (cp)[0] = (unsigned char)((value) >> 24); \ + (cp)[1] = (unsigned char)((value) >> 16); \ + (cp)[2] = (unsigned char)((value) >> 8); \ + (cp)[3] = (unsigned char)(value); } + +#if 0 +#define DEBUG_DSS +#else +#define diagbn(x,y) +#endif + +static void getstring(char **data, int *datalen, char **p, int *length) { + *p = NULL; + if (*datalen < 4) + return; + *length = GET_32BIT(*data); + *datalen -= 4; *data += 4; + if (*datalen < *length) + return; + *p = *data; + *data += *length; *datalen -= *length; +} +static Bignum getmp(char **data, int *datalen) { + char *p; + int length; + Bignum b; + + getstring(data, datalen, &p, &length); + if (!p) + return NULL; + if (p[0] & 0x80) + return NULL; /* negative mp */ + b = bignum_from_bytes(p, length); + return b; +} + +static Bignum get160(char **data, int *datalen) { + Bignum b; + + b = bignum_from_bytes(*data, 20); + *data += 20; *datalen -= 20; + + return b; +} + +struct dss_key { + Bignum p, q, g, y; +}; + +static void *dss_newkey(char *data, int len) { + char *p; + int slen; + struct dss_key *dss; + + dss = smalloc(sizeof(struct dss_key)); + if (!dss) return NULL; + getstring(&data, &len, &p, &slen); + +#ifdef DEBUG_DSS + { + int i; + printf("key:"); + for (i=0;ip = getmp(&data, &len); + dss->q = getmp(&data, &len); + dss->g = getmp(&data, &len); + dss->y = getmp(&data, &len); + + return dss; +} + +static void dss_freekey(void *key) { + struct dss_key *dss = (struct dss_key *)key; + freebn(dss->p); + freebn(dss->q); + freebn(dss->g); + freebn(dss->y); + sfree(dss); +} + +static char *dss_fmtkey(void *key) { + struct dss_key *dss = (struct dss_key *)key; + char *p; + int len, i, pos, nibbles; + static const char hex[] = "0123456789abcdef"; + if (!dss->p) + return NULL; + len = 8 + 4 + 1; /* 4 x "0x", punctuation, \0 */ + len += 4 * (ssh1_bignum_bitcount(dss->p)+15)/16; + len += 4 * (ssh1_bignum_bitcount(dss->q)+15)/16; + len += 4 * (ssh1_bignum_bitcount(dss->g)+15)/16; + len += 4 * (ssh1_bignum_bitcount(dss->y)+15)/16; + p = smalloc(len); + if (!p) return NULL; + + pos = 0; + pos += sprintf(p+pos, "0x"); + nibbles = (3 + ssh1_bignum_bitcount(dss->p))/4; if (nibbles<1) nibbles=1; + for (i=nibbles; i-- ;) + p[pos++] = hex[(bignum_byte(dss->p, i/2) >> (4*(i%2))) & 0xF]; + pos += sprintf(p+pos, ",0x"); + nibbles = (3 + ssh1_bignum_bitcount(dss->q))/4; if (nibbles<1) nibbles=1; + for (i=nibbles; i-- ;) + p[pos++] = hex[(bignum_byte(dss->q, i/2) >> (4*(i%2))) & 0xF]; + pos += sprintf(p+pos, ",0x"); + nibbles = (3 + ssh1_bignum_bitcount(dss->g))/4; if (nibbles<1) nibbles=1; + for (i=nibbles; i-- ;) + p[pos++] = hex[(bignum_byte(dss->g, i/2) >> (4*(i%2))) & 0xF]; + pos += sprintf(p+pos, ",0x"); + nibbles = (3 + ssh1_bignum_bitcount(dss->y))/4; if (nibbles<1) nibbles=1; + for (i=nibbles; i-- ;) + p[pos++] = hex[(bignum_byte(dss->y, i/2) >> (4*(i%2))) & 0xF]; + p[pos] = '\0'; + return p; +} + +static char *dss_fingerprint(void *key) { + struct dss_key *dss = (struct dss_key *)key; + struct MD5Context md5c; + unsigned char digest[16], lenbuf[4]; + char buffer[16*3+40]; + char *ret; + int numlen, i; + + MD5Init(&md5c); + MD5Update(&md5c, "\0\0\0\7ssh-dss", 11); + +#define ADD_BIGNUM(bignum) \ + numlen = (ssh1_bignum_bitcount(bignum)+8)/8; \ + PUT_32BIT(lenbuf, numlen); MD5Update(&md5c, lenbuf, 4); \ + for (i = numlen; i-- ;) { \ + unsigned char c = bignum_byte(bignum, i); \ + MD5Update(&md5c, &c, 1); \ + } + ADD_BIGNUM(dss->p); + ADD_BIGNUM(dss->q); + ADD_BIGNUM(dss->g); + ADD_BIGNUM(dss->y); +#undef ADD_BIGNUM + + MD5Final(digest, &md5c); + + sprintf(buffer, "%d ", ssh1_bignum_bitcount(dss->p)); + for (i = 0; i < 16; i++) + sprintf(buffer+strlen(buffer), "%s%02x", i?":":"", digest[i]); + ret = smalloc(strlen(buffer)+1); + if (ret) + strcpy(ret, buffer); + return ret; +} + +static int dss_verifysig(void *key, char *sig, int siglen, + char *data, int datalen) { + struct dss_key *dss = (struct dss_key *)key; + char *p; + int slen; + char hash[20]; + Bignum r, s, w, gu1p, yu2p, gu1yu2p, u1, u2, sha, v; + int ret; + + if (!dss->p) + return 0; + +#ifdef DEBUG_DSS + { + int i; + printf("sig:"); + for (i=0;i