X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/85cc02bb89053c7dc498759834121c1dbc946167..d8770b1245ff0acd81f581c5667563e0d127104a:/sshrsa.c diff --git a/sshrsa.c b/sshrsa.c index 9a62491a..36069ad7 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "ssh.h" @@ -205,7 +206,7 @@ static void *rsa2_newkey(char *data, int len) { if (!rsa) return NULL; getstring(&data, &len, &p, &slen); - if (!p || memcmp(p, "ssh-rsa", 7)) { + if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) { sfree(rsa); return NULL; } @@ -234,6 +235,108 @@ static char *rsa2_fmtkey(void *key) { return p; } +static unsigned char *rsa2_public_blob(void *key, int *len) { + struct RSAKey *rsa = (struct RSAKey *)key; + int elen, mlen, bloblen; + int i; + unsigned char *blob, *p; + + elen = (ssh1_bignum_bitcount(rsa->exponent)+8)/8; + mlen = (ssh1_bignum_bitcount(rsa->modulus)+8)/8; + + /* + * string "ssh-rsa", mpint exp, mpint mod. Total 19+elen+mlen. + * (three length fields, 12+7=19). + */ + bloblen = 19+elen+mlen; + blob = smalloc(bloblen); + p = blob; + PUT_32BIT(p, 7); p += 4; + memcpy(p, "ssh-rsa", 7); p += 7; + PUT_32BIT(p, elen); p += 4; + for (i = elen; i-- ;) *p++ = bignum_byte(rsa->exponent, i); + PUT_32BIT(p, mlen); p += 4; + for (i = mlen; i-- ;) *p++ = bignum_byte(rsa->modulus, i); + assert(p == blob + bloblen); + *len = bloblen; + return blob; +} + +static unsigned char *rsa2_private_blob(void *key, int *len) { + struct RSAKey *rsa = (struct RSAKey *)key; + int dlen, plen, qlen, ulen, bloblen; + int i; + unsigned char *blob, *p; + + dlen = (ssh1_bignum_bitcount(rsa->private_exponent)+8)/8; + plen = (ssh1_bignum_bitcount(rsa->p)+8)/8; + qlen = (ssh1_bignum_bitcount(rsa->q)+8)/8; + ulen = (ssh1_bignum_bitcount(rsa->iqmp)+8)/8; + + /* + * mpint private_exp, mpint p, mpint q, mpint iqmp. Total 16 + + * sum of lengths. + */ + bloblen = 16+dlen+plen+qlen+ulen; + blob = smalloc(bloblen); + p = blob; + PUT_32BIT(p, dlen); p += 4; + for (i = dlen; i-- ;) *p++ = bignum_byte(rsa->private_exponent, i); + PUT_32BIT(p, plen); p += 4; + for (i = plen; i-- ;) *p++ = bignum_byte(rsa->p, i); + PUT_32BIT(p, qlen); p += 4; + for (i = qlen; i-- ;) *p++ = bignum_byte(rsa->q, i); + PUT_32BIT(p, ulen); p += 4; + for (i = ulen; i-- ;) *p++ = bignum_byte(rsa->iqmp, i); + assert(p == blob + bloblen); + *len = bloblen; + return blob; +} + +static void *rsa2_createkey(unsigned char *pub_blob, int pub_len, + unsigned char *priv_blob, int priv_len) { + struct RSAKey *rsa; + char *pb = (char *)priv_blob; + + rsa = rsa2_newkey((char *)pub_blob, pub_len); + rsa->private_exponent = getmp(&pb, &priv_len); + rsa->p = getmp(&pb, &priv_len); + rsa->q = getmp(&pb, &priv_len); + rsa->iqmp = getmp(&pb, &priv_len); + + return rsa; +} + +static void *rsa2_openssh_createkey(unsigned char **blob, int *len) { + char **b = (char **)blob; + struct RSAKey *rsa; + + rsa = smalloc(sizeof(struct RSAKey)); + if (!rsa) return NULL; + rsa->comment = NULL; + + rsa->modulus = getmp(b, len); + rsa->exponent = getmp(b, len); + rsa->private_exponent = getmp(b, len); + rsa->iqmp = getmp(b, len); + rsa->p = getmp(b, len); + rsa->q = getmp(b, len); + + if (!rsa->modulus || !rsa->exponent || !rsa->private_exponent || + !rsa->iqmp || !rsa->p || !rsa->q) { + sfree(rsa->modulus); + sfree(rsa->exponent); + sfree(rsa->private_exponent); + sfree(rsa->iqmp); + sfree(rsa->p); + sfree(rsa->q); + sfree(rsa); + return NULL; + } + + return rsa; +} + static char *rsa2_fingerprint(void *key) { struct RSAKey *rsa = (struct RSAKey *)key; struct MD5Context md5c; @@ -258,7 +361,7 @@ static char *rsa2_fingerprint(void *key) { MD5Final(digest, &md5c); - sprintf(buffer, "%d ", ssh1_bignum_bitcount(rsa->modulus)); + sprintf(buffer, "ssh-rsa %d ", ssh1_bignum_bitcount(rsa->modulus)); for (i = 0; i < 16; i++) sprintf(buffer+strlen(buffer), "%s%02x", i?":":"", digest[i]); ret = smalloc(strlen(buffer)+1); @@ -287,6 +390,8 @@ static unsigned char asn1_weird_stuff[] = { 0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14, }; +#define ASN1_LEN ( (int) sizeof(asn1_weird_stuff) ) + static int rsa2_verifysig(void *key, char *sig, int siglen, char *data, int datalen) { struct RSAKey *rsa = (struct RSAKey *)key; @@ -314,12 +419,12 @@ static int rsa2_verifysig(void *key, char *sig, int siglen, if (bignum_byte(out, bytes-2) != 1) ret = 0; /* Most of the rest should be FF. */ - for (i = bytes-3; i >= 20 + sizeof(asn1_weird_stuff); i--) { + for (i = bytes-3; i >= 20 + ASN1_LEN; i--) { if (bignum_byte(out, i) != 0xFF) ret = 0; } /* Then we expect to see the asn1_weird_stuff. */ - for (i = 20 + sizeof(asn1_weird_stuff) - 1, j=0; i >= 20; i--,j++) { + for (i = 20 + ASN1_LEN - 1, j=0; i >= 20; i--,j++) { if (bignum_byte(out, i) != asn1_weird_stuff[j]) ret = 0; } @@ -333,15 +438,54 @@ static int rsa2_verifysig(void *key, char *sig, int siglen, return ret; } -int rsa2_sign(void *key, char *sig, int siglen, - char *data, int datalen) { - return 0; /* FIXME */ +unsigned char *rsa2_sign(void *key, char *data, int datalen, int *siglen) { + struct RSAKey *rsa = (struct RSAKey *)key; + unsigned char *bytes; + int nbytes; + unsigned char hash[20]; + Bignum in, out; + int i, j; + + SHA_Simple(data, datalen, hash); + + nbytes = (ssh1_bignum_bitcount(rsa->modulus)-1) / 8; + bytes = smalloc(nbytes); + + bytes[0] = 1; + for (i = 1; i < nbytes-20-ASN1_LEN; i++) + bytes[i] = 0xFF; + for (i = nbytes-20-ASN1_LEN, j=0; i < nbytes-20; i++,j++) + bytes[i] = asn1_weird_stuff[j]; + for (i = nbytes-20, j=0; i < nbytes; i++,j++) + bytes[i] = hash[j]; + + in = bignum_from_bytes(bytes, nbytes); + sfree(bytes); + + out = modpow(in, rsa->private_exponent, rsa->modulus); + freebn(in); + + nbytes = (ssh1_bignum_bitcount(out)+7)/8; + bytes = smalloc(4+7+4+nbytes); + PUT_32BIT(bytes, 7); + memcpy(bytes+4, "ssh-rsa", 7); + PUT_32BIT(bytes+4+7, nbytes); + for (i = 0; i < nbytes; i++) + bytes[4+7+4+i] = bignum_byte(out, nbytes-1-i); + freebn(out); + + *siglen = 4+7+4+nbytes; + return bytes; } -struct ssh_signkey ssh_rsa = { +const struct ssh_signkey ssh_rsa = { rsa2_newkey, rsa2_freekey, rsa2_fmtkey, + rsa2_public_blob, + rsa2_private_blob, + rsa2_createkey, + rsa2_openssh_createkey, rsa2_fingerprint, rsa2_verifysig, rsa2_sign,