1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-13 09:07:33 -05:00

Clean up ssh_keyalg APIs and implementations.

Quite a few of the function pointers in the ssh_keyalg vtable now take
ptrlen arguments in place of separate pointer and length pairs.
Meanwhile, the various key types' implementations of those functions
now work by initialising a BinarySource with the input ptrlen and
using the new decode functions to walk along it.

One exception is the openssh_createkey method which reads a private
key in the wire format used by OpenSSH's SSH-2 agent protocol, which
has to consume a prefix of a larger data stream, and tell the caller
how much of that data was the private key. That function now takes an
actual BinarySource, and passes that directly to the decode functions,
so that on return the caller finds that the BinarySource's read
pointer has been advanced exactly past the private key.

This let me throw away _several_ reimplementations of mpint-reading
functions, one in each of sshrsa, sshdss.c and sshecc.c. Worse still,
they didn't all have exactly the SSH-2 semantics, because the thing in
sshrsa.c whose name suggested it was an mpint-reading function
actually tolerated the wrong number of leading zero bytes, which it
had to be able to do to cope with the "ssh-rsa" signature format which
contains a thing that isn't quite an SSH-2 mpint. Now that deviation
is clearly commented!
This commit is contained in:
Simon Tatham
2018-05-31 18:40:51 +01:00
parent 5be57af173
commit ae3edcdfc0
9 changed files with 192 additions and 378 deletions

137
sshrsa.c
View File

@ -520,62 +520,27 @@ void freersakey(struct RSAKey *key)
* Implementation of the ssh-rsa signing key type.
*/
static void getstring(const char **data, int *datalen,
const char **p, int *length)
{
*p = NULL;
if (*datalen < 4)
return;
*length = toint(GET_32BIT(*data));
if (*length < 0)
return;
*datalen -= 4;
*data += 4;
if (*datalen < *length)
return;
*p = *data;
*data += *length;
*datalen -= *length;
}
static Bignum getmp(const char **data, int *datalen)
{
const char *p;
int length;
Bignum b;
getstring(data, datalen, &p, &length);
if (!p)
return NULL;
b = bignum_from_bytes(p, length);
return b;
}
static void rsa2_freekey(ssh_key *key); /* forward reference */
static ssh_key *rsa2_newkey(const ssh_keyalg *self,
const void *vdata, int len)
static ssh_key *rsa2_newkey(const ssh_keyalg *self, ptrlen data)
{
const char *p;
const char *data = (const char *)vdata;
int slen;
BinarySource src[1];
struct RSAKey *rsa;
rsa = snew(struct RSAKey);
getstring(&data, &len, &p, &slen);
if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) {
sfree(rsa);
BinarySource_BARE_INIT(src, data.ptr, data.len);
if (!ptrlen_eq_string(get_string(src), "ssh-rsa"))
return NULL;
}
rsa->exponent = getmp(&data, &len);
rsa->modulus = getmp(&data, &len);
rsa = snew(struct RSAKey);
rsa->exponent = get_mp_ssh2(src);
rsa->modulus = get_mp_ssh2(src);
rsa->private_exponent = NULL;
rsa->p = rsa->q = rsa->iqmp = NULL;
rsa->comment = NULL;
if (!rsa->exponent || !rsa->modulus) {
rsa2_freekey(&rsa->sshk);
return NULL;
if (get_err(src)) {
rsa2_freekey(&rsa->sshk);
return NULL;
}
return &rsa->sshk;
@ -620,24 +585,24 @@ static void rsa2_private_blob(ssh_key *key, BinarySink *bs)
}
static ssh_key *rsa2_createkey(const ssh_keyalg *self,
const void *pub_blob, int pub_len,
const void *priv_blob, int priv_len)
ptrlen pub, ptrlen priv)
{
BinarySource src[1];
ssh_key *sshk;
struct RSAKey *rsa;
const char *pb = (const char *) priv_blob;
sshk = rsa2_newkey(self, pub_blob, pub_len);
sshk = rsa2_newkey(self, pub);
if (!sshk)
return NULL;
rsa = FROMFIELD(sshk, struct RSAKey, sshk);
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);
BinarySource_BARE_INIT(src, priv.ptr, priv.len);
rsa->private_exponent = get_mp_ssh2(src);
rsa->p = get_mp_ssh2(src);
rsa->q = get_mp_ssh2(src);
rsa->iqmp = get_mp_ssh2(src);
if (!rsa_verify(rsa)) {
if (get_err(src) || !rsa_verify(rsa)) {
rsa2_freekey(&rsa->sshk);
return NULL;
}
@ -646,28 +611,21 @@ static ssh_key *rsa2_createkey(const ssh_keyalg *self,
}
static ssh_key *rsa2_openssh_createkey(const ssh_keyalg *self,
const unsigned char **blob, int *len)
BinarySource *src)
{
const char **b = (const char **) blob;
struct RSAKey *rsa;
rsa = snew(struct RSAKey);
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);
rsa->modulus = get_mp_ssh2(src);
rsa->exponent = get_mp_ssh2(src);
rsa->private_exponent = get_mp_ssh2(src);
rsa->iqmp = get_mp_ssh2(src);
rsa->p = get_mp_ssh2(src);
rsa->q = get_mp_ssh2(src);
if (!rsa->modulus || !rsa->exponent || !rsa->private_exponent ||
!rsa->iqmp || !rsa->p || !rsa->q) {
rsa2_freekey(&rsa->sshk);
return NULL;
}
if (!rsa_verify(rsa)) {
if (get_err(src) || !rsa_verify(rsa)) {
rsa2_freekey(&rsa->sshk);
return NULL;
}
@ -687,14 +645,13 @@ static void rsa2_openssh_fmtkey(ssh_key *key, BinarySink *bs)
put_mp_ssh2(bs, rsa->q);
}
static int rsa2_pubkey_bits(const ssh_keyalg *self,
const void *blob, int len)
static int rsa2_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
{
ssh_key *sshk;
struct RSAKey *rsa;
int ret;
sshk = rsa2_newkey(self, blob, len);
sshk = rsa2_newkey(self, pub);
if (!sshk)
return -1;
@ -736,24 +693,32 @@ static const unsigned char asn1_weird_stuff[] = {
#define ASN1_LEN ( (int) sizeof(asn1_weird_stuff) )
static int rsa2_verifysig(ssh_key *key, const void *vsig, int siglen,
const void *data, int datalen)
static int rsa2_verifysig(ssh_key *key, ptrlen sig, ptrlen data)
{
struct RSAKey *rsa = FROMFIELD(key, struct RSAKey, sshk);
const char *sig = (const char *)vsig;
BinarySource src[1];
ptrlen type, in_pl;
Bignum in, out;
const char *p;
int slen;
int bytes, i, j, ret;
unsigned char hash[20];
getstring(&sig, &siglen, &p, &slen);
if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) {
BinarySource_BARE_INIT(src, sig.ptr, sig.len);
type = get_string(src);
/*
* RFC 4253 section 6.6: the signature integer in an ssh-rsa
* signature is 'without lengths or padding'. That is, we _don't_
* expect the usual leading zero byte if the topmost bit of the
* first byte is set. (However, because of the possibility of
* BUG_SSH2_RSA_PADDING at the other end, we tolerate it if it's
* there.) So we can't use get_mp_ssh2, which enforces that
* leading-byte scheme; instead we use get_string and
* bignum_from_bytes, which will tolerate anything.
*/
in_pl = get_string(src);
if (get_err(src) || !ptrlen_eq_string(type, "ssh-rsa"))
return 0;
}
in = getmp(&sig, &siglen);
if (!in)
return 0;
in = bignum_from_bytes(in_pl.ptr, in_pl.len);
out = modpow(in, rsa->exponent, rsa->modulus);
freebn(in);
@ -777,7 +742,7 @@ static int rsa2_verifysig(ssh_key *key, const void *vsig, int siglen,
ret = 0;
}
/* Finally, we expect to see the SHA-1 hash of the signed data. */
SHA_Simple(data, datalen, hash);
SHA_Simple(data.ptr, data.len, hash);
for (i = 19, j = 0; i >= 0; i--, j++) {
if (bignum_byte(out, i) != hash[j])
ret = 0;
@ -846,7 +811,7 @@ const ssh_keyalg ssh_rsa = {
struct RSAKey *ssh_rsakex_newkey(const void *data, int len)
{
ssh_key *sshk = rsa2_newkey(&ssh_rsa, data, len);
ssh_key *sshk = rsa2_newkey(&ssh_rsa, make_ptrlen(data, len));
if (!sshk)
return NULL;
return FROMFIELD(sshk, struct RSAKey, sshk);