1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Support SHA-256 and SHA-512 based RSA signatures.

Now the RSA signing function supports the two flags defined in
draft-miller-ssh-agent-02, and uses them to generate RSA signatures
based on SHA-256 and SHA-512, which look exactly like the ordinary
kind of RSA SHA-1 signature except that the decoded signature integer
has a different hash at the bottom and an ASN.1 identifying prefix to
match, and also the signature-type string prefixing the integer
changes from "ssh-rsa" to "rsa-sha2-256" or "rsa-sha2-512" as
appropriate.

We don't _accept_ signatures of these new types - that would need an
entirely different protocol extension - and we don't generate them
under any circumstances other than Pageant receiving a sign request
with one of those flags set.
This commit is contained in:
Simon Tatham 2018-11-19 20:46:59 +00:00
parent 7d4a276fc1
commit 13b29008b4
2 changed files with 62 additions and 15 deletions

6
ssh.h
View File

@ -807,6 +807,12 @@ struct ssh_keyalg {
#define ssh_key_ssh_id(key) ((*(key))->ssh_id)
#define ssh_key_cache_id(key) ((*(key))->cache_id)
/*
* Enumeration of signature flags from draft-miller-ssh-agent-02
*/
#define SSH_AGENT_RSA_SHA2_256 2
#define SSH_AGENT_RSA_SHA2_512 4
typedef struct ssh_compressor {
const struct ssh_compression_alg *vt;
} ssh_compressor;

View File

@ -676,12 +676,28 @@ static int rsa2_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
* iso(1) identified-organization(3) oiw(14) secsig(3)
* algorithms(2) 26 }
*/
static const unsigned char asn1_weird_stuff[] = {
static const unsigned char sha1_asn1_prefix[] = {
0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B,
0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14,
};
#define ASN1_LEN ( (int) sizeof(asn1_weird_stuff) )
/*
* Two more similar pieces of ASN.1 used for signatures using SHA-256
* and SHA-512, in the same format but differing only in various
* length fields and OID.
*/
static const unsigned char sha256_asn1_prefix[] = {
0x00, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
0x05, 0x00, 0x04, 0x20,
};
static const unsigned char sha512_asn1_prefix[] = {
0x00, 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60,
0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
0x05, 0x00, 0x04, 0x40,
};
#define SHA1_ASN1_PREFIX_LEN sizeof(sha1_asn1_prefix)
static bool rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data)
{
@ -723,13 +739,13 @@ static bool rsa2_verify(ssh_key *key, ptrlen sig, ptrlen data)
if (bignum_byte(out, bytes - 2) != 1)
toret = false;
/* Most of the rest should be FF. */
for (i = bytes - 3; i >= 20 + ASN1_LEN; i--) {
for (i = bytes - 3; i >= 20 + SHA1_ASN1_PREFIX_LEN; i--) {
if (bignum_byte(out, i) != 0xFF)
toret = false;
}
/* Then we expect to see the asn1_weird_stuff. */
for (i = 20 + ASN1_LEN - 1, j = 0; i >= 20; i--, j++) {
if (bignum_byte(out, i) != asn1_weird_stuff[j])
/* Then we expect to see the sha1_asn1_prefix. */
for (i = 20 + SHA1_ASN1_PREFIX_LEN - 1, j = 0; i >= 20; i--, j++) {
if (bignum_byte(out, i) != sha1_asn1_prefix[j])
toret = false;
}
/* Finally, we expect to see the SHA-1 hash of the signed data. */
@ -749,22 +765,47 @@ static void rsa2_sign(ssh_key *key, const void *data, int datalen,
struct RSAKey *rsa = container_of(key, struct RSAKey, sshk);
unsigned char *bytes;
int nbytes;
unsigned char hash[20];
unsigned char hash[64];
Bignum in, out;
int i, j;
const struct ssh_hashalg *halg;
ssh_hash *h;
const unsigned char *asn1_prefix;
unsigned asn1_prefix_size;
const char *sign_alg_name;
SHA_Simple(data, datalen, hash);
if (flags & SSH_AGENT_RSA_SHA2_256) {
halg = &ssh_sha256;
asn1_prefix = sha256_asn1_prefix;
asn1_prefix_size = sizeof(sha256_asn1_prefix);
sign_alg_name = "rsa-sha2-256";
} else if (flags & SSH_AGENT_RSA_SHA2_512) {
halg = &ssh_sha512;
asn1_prefix = sha512_asn1_prefix;
asn1_prefix_size = sizeof(sha512_asn1_prefix);
sign_alg_name = "rsa-sha2-512";
} else {
halg = &ssh_sha1;
asn1_prefix = sha1_asn1_prefix;
asn1_prefix_size = sizeof(sha1_asn1_prefix);
sign_alg_name = "ssh-rsa";
}
h = ssh_hash_new(halg);
put_data(h, data, datalen);
ssh_hash_final(h, hash);
nbytes = (bignum_bitcount(rsa->modulus) - 1) / 8;
assert(1 <= nbytes - 20 - ASN1_LEN);
assert(1 <= nbytes - halg->hlen - asn1_prefix_size);
bytes = snewn(nbytes, unsigned char);
bytes[0] = 1;
for (i = 1; i < nbytes - 20 - ASN1_LEN; i++)
for (i = 1; i < nbytes - halg->hlen - asn1_prefix_size; 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++)
for (i = nbytes - halg->hlen - asn1_prefix_size, j = 0;
i < nbytes - halg->hlen; i++, j++)
bytes[i] = asn1_prefix[j];
for (i = nbytes - halg->hlen, j = 0; i < nbytes; i++, j++)
bytes[i] = hash[j];
in = bignum_from_bytes(bytes, nbytes);
@ -773,7 +814,7 @@ static void rsa2_sign(ssh_key *key, const void *data, int datalen,
out = rsa_privkey_op(in, rsa);
freebn(in);
put_stringz(bs, "ssh-rsa");
put_stringz(bs, sign_alg_name);
nbytes = (bignum_bitcount(out) + 7) / 8;
put_uint32(bs, nbytes);
for (i = 0; i < nbytes; i++)
@ -800,7 +841,7 @@ const ssh_keyalg ssh_rsa = {
"ssh-rsa",
"rsa2",
NULL,
0, /* no supported flags */
SSH_AGENT_RSA_SHA2_256 | SSH_AGENT_RSA_SHA2_512,
};
struct RSAKey *ssh_rsakex_newkey(const void *data, int len)