X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=sshdss.c;h=3682ad69e8ce85e223945e1965d58fb7281ddbef;hb=f004bcca17a789356c32527a396b68b71a773db2;hp=2b19a921f6c6ce22689334a662169f0b29a9070b;hpb=6184e9f95d3c952f9d9b99c3555a2cdb5d02fe05;p=PuTTY.git diff --git a/sshdss.c b/sshdss.c index 2b19a921..3682ad69 100644 --- a/sshdss.c +++ b/sshdss.c @@ -82,6 +82,8 @@ static Bignum get160(char **data, int *datalen) return b; } +static void dss_freekey(void *key); /* forward reference */ + static void *dss_newkey(char *data, int len) { char *p; @@ -89,8 +91,6 @@ static void *dss_newkey(char *data, int len) struct dss_key *dss; dss = snew(struct dss_key); - if (!dss) - return NULL; getstring(&data, &len, &p, &slen); #ifdef DEBUG_DSS @@ -111,6 +111,14 @@ static void *dss_newkey(char *data, int len) dss->q = getmp(&data, &len); dss->g = getmp(&data, &len); dss->y = getmp(&data, &len); + dss->x = NULL; + + if (!dss->p || !dss->q || !dss->g || !dss->y || + !bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) { + /* Invalid key. */ + dss_freekey(dss); + return NULL; + } return dss; } @@ -118,10 +126,16 @@ static void *dss_newkey(char *data, int len) 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); + if (dss->p) + freebn(dss->p); + if (dss->q) + freebn(dss->q); + if (dss->g) + freebn(dss->g); + if (dss->y) + freebn(dss->y); + if (dss->x) + freebn(dss->x); sfree(dss); } @@ -254,13 +268,29 @@ static int dss_verifysig(void *key, char *sig, int siglen, } r = get160(&sig, &siglen); s = get160(&sig, &siglen); - if (!r || !s) + if (!r || !s) { + if (r) + freebn(r); + if (s) + freebn(s); return 0; + } + + if (!bignum_cmp(s, Zero)) { + freebn(r); + freebn(s); + return 0; + } /* * Step 1. w <- s^-1 mod q. */ w = modinv(s, dss->q); + if (!w) { + freebn(r); + freebn(s); + return 0; + } /* * Step 2. u1 <- SHA(message) * w mod q. @@ -384,7 +414,13 @@ static void *dss_createkey(unsigned char *pub_blob, int pub_len, Bignum ytest; dss = dss_newkey((char *) pub_blob, pub_len); + if (!dss) + return NULL; dss->x = getmp(&pb, &priv_len); + if (!dss->x) { + dss_freekey(dss); + return NULL; + } /* * Check the obsolete hash in the old DSS key format. @@ -423,8 +459,6 @@ static void *dss_openssh_createkey(unsigned char **blob, int *len) struct dss_key *dss; dss = snew(struct dss_key); - if (!dss) - return NULL; dss->p = getmp(b, len); dss->q = getmp(b, len); @@ -432,14 +466,11 @@ static void *dss_openssh_createkey(unsigned char **blob, int *len) dss->y = getmp(b, len); dss->x = getmp(b, len); - if (!dss->p || !dss->q || !dss->g || !dss->y || !dss->x) { - sfree(dss->p); - sfree(dss->q); - sfree(dss->g); - sfree(dss->y); - sfree(dss->x); - sfree(dss); - return NULL; + if (!dss->p || !dss->q || !dss->g || !dss->y || !dss->x || + !bignum_cmp(dss->q, Zero) || !bignum_cmp(dss->p, Zero)) { + /* Invalid key. */ + dss_freekey(dss); + return NULL; } return dss; @@ -479,13 +510,16 @@ static int dss_pubkey_bits(void *blob, int len) int ret; dss = dss_newkey((char *) blob, len); + if (!dss) + return -1; ret = bignum_bitcount(dss->p); dss_freekey(dss); return ret; } -static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen) +Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key, + unsigned char *digest, int digest_len) { /* * The basic DSS signing algorithm is: @@ -558,21 +592,16 @@ static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen) * Computer Security Group for helping to argue out all the * fine details. */ - struct dss_key *dss = (struct dss_key *) key; SHA512_State ss; - unsigned char digest[20], digest512[64]; - Bignum proto_k, k, gkp, hash, kinv, hxr, r, s; - unsigned char *bytes; - int nbytes, i; - - SHA_Simple(data, datalen, digest); + unsigned char digest512[64]; + Bignum proto_k, k; /* * Hash some identifying text plus x. */ SHA512_Init(&ss); - SHA512_Bytes(&ss, "DSA deterministic k generator", 30); - sha512_mpint(&ss, dss->x); + SHA512_Bytes(&ss, id_string, strlen(id_string) + 1); + sha512_mpint(&ss, private_key); SHA512_Final(&ss, digest512); /* @@ -580,19 +609,49 @@ static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen) */ SHA512_Init(&ss); SHA512_Bytes(&ss, digest512, sizeof(digest512)); - SHA512_Bytes(&ss, digest, sizeof(digest)); - SHA512_Final(&ss, digest512); + SHA512_Bytes(&ss, digest, digest_len); + + while (1) { + SHA512_State ss2 = ss; /* structure copy */ + SHA512_Final(&ss2, digest512); + + smemclr(&ss2, sizeof(ss2)); + + /* + * Now convert the result into a bignum, and reduce it mod q. + */ + proto_k = bignum_from_bytes(digest512, 64); + k = bigmod(proto_k, modulus); + freebn(proto_k); + + if (bignum_cmp(k, One) != 0 && bignum_cmp(k, Zero) != 0) { + smemclr(&ss, sizeof(ss)); + smemclr(digest512, sizeof(digest512)); + return k; + } + + /* Very unlikely we get here, but if so, k was unsuitable. */ + freebn(k); + /* Perturb the hash to think of a different k. */ + SHA512_Bytes(&ss, "x", 1); + /* Go round and try again. */ + } +} - smemclr(&ss, sizeof(ss)); +static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen) +{ + struct dss_key *dss = (struct dss_key *) key; + Bignum k, gkp, hash, kinv, hxr, r, s; + unsigned char digest[20]; + unsigned char *bytes; + int nbytes, i; - /* - * Now convert the result into a bignum, and reduce it mod q. - */ - proto_k = bignum_from_bytes(digest512, 64); - k = bigmod(proto_k, dss->q); - freebn(proto_k); + SHA_Simple(data, datalen, digest); - smemclr(digest512, sizeof(digest512)); + k = dss_gen_k("DSA deterministic k generator", dss->q, dss->x, + digest, sizeof(digest)); + kinv = modinv(k, dss->q); /* k^-1 mod q */ + assert(kinv); /* * Now we have k, so just go ahead and compute the signature. @@ -602,11 +661,11 @@ static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen) freebn(gkp); hash = bignum_from_bytes(digest, 20); - kinv = modinv(k, dss->q); /* k^-1 mod q */ hxr = bigmuladd(dss->x, r, hash); /* hash + x*r */ s = modmul(kinv, hxr, dss->q); /* s = k^-1 * (hash + x*r) mod q */ freebn(hxr); freebn(kinv); + freebn(k); freebn(hash); /*