1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-16 02:27:32 -05:00

Introduce a centralised unmarshaller, 'BinarySource'.

This is the companion to the BinarySink system I introduced a couple
of weeks ago, and provides the same type-genericity which will let me
use the same get_* routines on an SSH packet, an SFTP packet or
anything else that chooses to include an implementing substructure.

However, unlike BinarySink which contained a (one-function) vtable,
BinarySource contains only mutable data fields - so another thing you
might very well want to do is to simply instantiate a bare one without
any containing object at all. I couldn't quite coerce C into letting
me use the same setup macro in both cases, so I've arranged a
BinarySource_INIT you can use on larger implementing objects and a
BinarySource_BARE_INIT you can use on a BinarySource not contained in
anything.

The API follows the general principle that even if decoding fails, the
decode functions will always return _some_ kind of value, with the
same dynamically-allocated-ness they would have used for a completely
successful value. But they also set an error flag in the BinarySource
which can be tested later. So instead of having to decode a 10-field
packet by means of 10 separate 'if (!get_foo(src)) throw error'
clauses, you can just write 10 'variable = get_foo(src)' statements
followed by a single check of get_err(src), and if the error check
fails, you have to do exactly the same set of frees you would have
after a successful decode.
This commit is contained in:
Simon Tatham
2018-06-02 08:25:19 +01:00
parent 9e96af59ce
commit 005ca6b257
6 changed files with 306 additions and 4 deletions

42
sshbn.c
View File

@ -1624,12 +1624,12 @@ int ssh1_write_bignum(void *data, Bignum bn)
void BinarySink_put_mp_ssh1(BinarySink *bs, Bignum bn)
{
int len = ssh1_bignum_length(bn);
int bits = bignum_bitcount(bn);
int bytes = (bits + 7) / 8;
int i;
int bitc = bignum_bitcount(bn);
put_uint16(bs, bitc);
for (i = len - 2; i--;)
put_uint16(bs, bits);
for (i = bytes; i--;)
put_byte(bs, bignum_byte(bn, i));
}
@ -1643,6 +1643,40 @@ void BinarySink_put_mp_ssh2(BinarySink *bs, Bignum bn)
put_byte(bs, bignum_byte(bn, i));
}
Bignum BinarySource_get_mp_ssh1(BinarySource *src)
{
unsigned bitc = get_uint16(src);
ptrlen bytes = get_data(src, (bitc + 7) / 8);
if (get_err(src)) {
return bignum_from_long(0);
} else {
Bignum toret = bignum_from_bytes(bytes.ptr, bytes.len);
if (bignum_bitcount(toret) != bitc) {
src->err = BSE_INVALID;
freebn(toret);
toret = bignum_from_long(0);
}
return toret;
}
}
Bignum BinarySource_get_mp_ssh2(BinarySource *src)
{
ptrlen bytes = get_string(src);
if (get_err(src)) {
return bignum_from_long(0);
} else {
const unsigned char *p = bytes.ptr;
if ((bytes.len > 0 &&
((p[0] & 0x80) ||
(p[0] == 0 && (bytes.len <= 1 || !(p[1] & 0x80)))))) {
src->err = BSE_INVALID;
return bignum_from_long(0);
}
return bignum_from_bytes(bytes.ptr, bytes.len);
}
}
/*
* Compare two bignums. Returns like strcmp.
*/