The old 'Bignum' data type is gone completely, and so is sshbn.c. In
its place is a new thing called 'mp_int', handled by an entirely new
library module mpint.c, with API differences both large and small.
The main aim of this change is that the new library should be free of
timing- and cache-related side channels. I've written the code so that
it _should_ - assuming I haven't made any mistakes - do all of its
work without either control flow or memory addressing depending on the
data words of the input numbers. (Though, being an _arbitrary_
precision library, it does have to at least depend on the sizes of the
numbers - but there's a 'formal' size that can vary separately from
the actual magnitude of the represented integer, so if you want to
keep it secret that your number is actually small, it should work fine
to have a very long mp_int and just happen to store 23 in it.) So I've
done all my conditionalisation by means of computing both answers and
doing bit-masking to swap the right one into place, and all loops over
the words of an mp_int go up to the formal size rather than the actual
size.
I haven't actually tested the constant-time property in any rigorous
way yet (I'm still considering the best way to do it). But this code
is surely at the very least a big improvement on the old version, even
if I later find a few more things to fix.
I've also completely rewritten the low-level elliptic curve arithmetic
from sshecc.c; the new ecc.c is closer to being an adjunct of mpint.c
than it is to the SSH end of the code. The new elliptic curve code
keeps all coordinates in Montgomery-multiplication transformed form to
speed up all the multiplications mod the same prime, and only converts
them back when you ask for the affine coordinates. Also, I adopted
extended coordinates for the Edwards curve implementation.
sshecc.c has also had a near-total rewrite in the course of switching
it over to the new system. While I was there, I've separated ECDSA and
EdDSA more completely - they now have separate vtables, instead of a
single vtable in which nearly every function had a big if statement in
it - and also made the externally exposed types for an ECDSA key and
an ECDH context different.
A minor new feature: since the new arithmetic code includes a modular
square root function, we can now support the compressed point
representation for the NIST curves. We seem to have been getting along
fine without that so far, but it seemed a shame not to put it in,
since it was suddenly easy.
In sshrsa.c, one major change is that I've removed the RSA blinding
step in rsa_privkey_op, in which we randomise the ciphertext before
doing the decryption. The purpose of that was to avoid timing leaks
giving away the plaintext - but the new arithmetic code should take
that in its stride in the course of also being careful enough to avoid
leaking the _private key_, which RSA blinding had no way to do
anything about in any case.
Apart from those specific points, most of the rest of the changes are
more or less mechanical, just changing type names and translating code
into the new API.
The gdb version of container_of can do better than the C function,
because you don't have to specify the structure field name if it can
be inferred from the type of the input expression.
And $list234 can be made to automatically list the contents of each
tree element, not just a pointer to it - just the thing for looking
quickly through sktree or s->channels to find the one you're after.
This commit includes <stdbool.h> from defs.h and deletes my
traditional definitions of TRUE and FALSE, but other than that, it's a
100% mechanical search-and-replace transforming all uses of TRUE and
FALSE into the C99-standardised lowercase spellings.
No actual types are changed in this commit; that will come next. This
is just getting the noise out of the way, so that subsequent commits
can have a higher proportion of signal.
These are things where no fix was actually necessary in the code, but
the FIXME indicated that the comment itself was either in need of a
rewrite or removal.
There was a while when I hadn't decided what the name of the program
was going to be, and apparently once I did I never got round to
substituting it back in everywhere.
All the main backend structures - Ssh, Telnet, Pty, Serial etc - now
describe structure types themselves rather than pointers to them. The
same goes for the codebase-wide trait types Socket and Plug, and the
supporting types SockAddr and Pinger.
All those things that were typedefed as pointers are older types; the
newer ones have the explicit * at the point of use, because that's
what I now seem to be preferring. But whichever one of those is
better, inconsistently using a mixture of the two styles is worse, so
let's make everything consistent.
A few types are still implicitly pointers, such as Bignum and some of
the GSSAPI types; generally this is either because they have to be
void *, or because they're typedefed differently on different
platforms and aren't always pointers at all. Can't be helped. But I've
got rid of the main ones, at least.
I've been playing around with GDB's Python scripting system recently,
and this is a thing I've always thought it would be nice to be able to
do: if you load this script (which, on Ubuntu 18.04's gdb, is as
simple as 'source contrib/gdb.py' at the gdb prompt, or similar), then
variables of type Bignum will be printed as (e.g.) 'Bignum(0x12345)',
or 'Bignum(NULL)' if they're null pointers, or a fallback
representation if they're non-null pointers but gdb can't read
anything sensible from them.
This is a cleanup I started to notice a need for during the BinarySink
work. It removes a lot of faffing about casting things to char * or
unsigned char * so that some API will accept them, even though lots of
such APIs really take a plain 'block of raw binary data' argument and
don't care what C thinks the signedness of that data might be - they
may well reinterpret it back and forth internally.
So I've tried to arrange for all the function call APIs that ought to
have a void * (or const void *) to have one, and those that need to do
pointer arithmetic on the parameter internally can cast it back at the
top of the function. That saves endless ad-hoc casts at the call
sites.
Used the wrong kind of brackets when initialising the actual hash (as
opposed to hash ref) %disc_reasons. Not sure how I didn't notice the
warning in yesterday's testing!
I'm increasingly wishing I'd written this parsing program in Python,
and yet another reason why is that using argparse for the command-line
handling makes it a lot harder to forget to write the --help text when
you add an extra option.
This makes it more feasible to use logparse.pl as an output filter on
a PuTTY SSH log file and discard the original file.
In particular, ever since commit b4fde270c, I've been finding it
useful when testing new code to direct my SSH logs to a named pipe and
have another terminal window give a real-time dump of them by running
'while cat $named_pipe; do :; done'. Now I can replace the 'cat' in
that shell command with 'logparse.pl -ve' and still get the Event Log
messages as well as the unpacked contents of all the packets.
This includes picking apart the various asymmetric crypto formats
(public keys, signatures, elliptic-curve point encodings) as far as
possible, but since the verbose decoder system in logparse.pl
currently has to work without benefit of statefulness, it's not always
possible - some of the ECC formats depend for their decoding on
everyone remembering _which_ ECC protocol was negotiated by the
KEXINITs.
The type code for an mpint in the input format string is "m", not
"mpint". This hasn't come up yet as far as I can see, but as and when
I add verbose dump routines for packet types that involve asymmetric
crypto, it will.
This allows me to request a verbose dump of the contents of some
particular packet type, or for all packet types.
Currently, the only packet type for which I've written a verbose dump
function is KEXINIT, but the framework is there to add further verbose
dumpers as and when they're needed.
Mark Wooding pointed out that my comment in make1305.py was completely
wrong, and that the stated strategy for reducing a value mod 2^130-5
would not in fact completely reduce all inputs in the range - for the
most obvious reason, namely that the numbers between 2^130-5 and 2^130
would never have anything subtracted at all.
Implemented a replacement strategy which my tests suggest will do the
right thing for all numbers in the expected range that are anywhere
near an integer multiple of the modulus.
It now expects its standard input to be connected to the same PuTTY
its standard output is talking to, i.e. expects to be invoked as a
proxy command. It conducts the same sample key exchange as it used to,
but now reads the SSH greeting and first couple of packets back from
PuTTY and minimally checks that they're something like what it was
expecting.
(In the process, I've also fixed a mistake in the Python message code
enumeration, which caused one of those expect() calls to fail.)
As I mentioned in the previous commit, I'm going to want PuTTY to be
able to run sensibly when compiled with 64-bit Visual Studio,
including handling bignums in 64-bit chunks for speed. Unfortunately,
64-bit VS does not provide any type we can use as BignumDblInt in that
situation (unlike 64-bit gcc and clang, which give us __uint128_t).
The only facilities it provides are compiler intrinsics to access an
add-with-carry operation and a 64x64->128 multiplication (the latter
delivering its product in two separate 64-bit output chunks).
Hence, here's a substantial rework of the bignum code to make it
implement everything in terms of _those_ primitives, rather than
depending throughout on having BignumDblInt available to use ad-hoc.
BignumDblInt does still exist, for the moment, but now it's an
internal implementation detail of sshbn.h, only declared inside a new
set of macros implementing arithmetic primitives, and not accessible
to any code outside sshbn.h (which confirms that I really did catch
all uses of it and remove them).
The resulting code is surprisingly nice-looking, actually. You'd
expect more hassle and roundabout circumlocutions when you drop down
to using a more basic set of primitive operations, but actually, in
many cases it's turned out shorter to write things in terms of the new
BignumADC and BignumMUL macros - because almost all my uses of
BignumDblInt were implementing those operations anyway, taking several
lines at a time, and now they can do each thing in just one line.
The biggest headache was Poly1305: I wasn't able to find any sensible
way to adapt the existing Python script that generates the various
per-int-size implementations of arithmetic mod 2^130-5, and so I had
to rewrite it from scratch instead, with nothing in common with the
old version beyond a handful of comments. But even that seems to have
worked out nicely: the new version has much more legible descriptions
of the high-level algorithms, by virtue of having a 'Multiprecision'
type which wraps up the division into words, and yet Multiprecision's
range analysis allows it to automatically drop out special cases such
as multiplication by 5 being much easier than multiplication by
another multi-word integer.
If a PuTTY SSH packet log has gone through line-wrapping at 72
columns, destroying the long lines of the packet hex dumps, then this
script will reconstitute it as best it can, by reconstructing the
ASCII section at the end of the dump from the (hopefully) undamaged
hex part, and using that to spot wrapped lines and remove the
subsequent debris.
Rather than doing arithmetic mod 2^130-5 using the general-purpose
Bignum library, which requires lots of mallocs and frees per operation
and also uses a general-purpose divide routine for each modular
reduction, we now have some dedicated routines in sshccp.c to do
arithmetic mod 2^130-5 in a more efficient way, and hopefully also
with data-independent performance.
Because PuTTY's target platforms don't all use the same size of bignum
component, I've arranged to auto-generate the arithmetic functions
using a Python script living in the 'contrib' directory. As and when
we need to support an extra BignumInt size, that script should still
be around to re-run with different arguments.
Installing this systemwide as the Windows text selection cursor is a
workaround for 'black-pointer'. It's a white I-beam with a one-pixel
black outline around it, so it should be visible on any background
colour. (I suppose that a backdrop of tightly packed I-beams looking
just like it might successfully hide it, but that's unlikely :-)
I constructed this some years ago for personal use; I needed it again
this week and had to go and recover it from a backup of a defunct
system, which made me think I really ought to check it in somewhere,
and this 'contrib' directory seems like the ideal place.
encodelib.py is a Python library which implements some handy SSH-2
encoding primitives; samplekex.py uses that to fabricate the start of
an SSH connection, up to the point where key exchange totally fails
its crypto.
The idea is that you adapt samplekex.py to construct initial-kex
sequences with particular properties, in order to test robustness and
security fixes that affect the initial-kex sequence. For example, I
used an adaptation of this to test the Diffie-Hellman range check
that's just gone into 0.64.
Bare string exceptions aren't supported any more.
Patch by Will Aoki, plus a backward compatibility tweak from Colin Watson.
Seen working with Python 2.4.3 and 2.7.6.
This provides support for ECDSA public keys, for both hosts and users,
and also ECDH key exchange. Supported curves are currently just the
three NIST curves required by RFC 5656.
I've shifted away from using the SVN revision number as a monotonic
version identifier (replacing it in the Windows version resource with
a count of days since an arbitrary epoch), and I've removed all uses
of SVN keyword expansion (replacing them with version information
written out by Buildscr).
While I'm at it, I've done a major rewrite of the affected code which
centralises all the computation of the assorted version numbers and
strings into Buildscr, so that they're all more or less alongside each
other rather than scattered across multiple source files.
I've also retired the MD5-based manifest file system. A long time ago,
it seemed like a good idea to arrange that binaries of PuTTY would
automatically cease to identify themselves as a particular upstream
version number if any changes were made to the source code, so that if
someone made a local tweak and distributed the result then I wouldn't
get blamed for the results. Since then I've decided the whole idea is
more trouble than it's worth, so now distribution tarballs will have
version information baked in and people can just cope with that.
[originally from svn r10262]
It looks as if it's never worked at all: it had a spurious second
printf, it completely forgot to allow for the uint32 type code that
SSH2_MSG_CHANNEL_DATA doesn't have, it accessed the channel state's
sequence number fields in a way that made no sense and didn't match
the rest of the program, *and* it misinvoked the file opening API. I
must have never had an occasion to test it.
[originally from svn r10037]
Previously it would throw a bunch of Perl undefined-variable-usage
warnings; now it cleanly detects the problem, dumps as much of the
message as it still reasonably can, and doesn't update any channel
states.
[originally from svn r10036]
doesn't have TIOCSCTTY, so my attempt to set the ctty of the child
process isn't doing anything, and only works by chance when you run
bash because bash does the thing that _will_ set the ctty, namely
opening the terminal file again without O_NOCTTY. So now we do that
too.
[originally from svn r9638]
In each case, want_reply was being treated as true even when it wasn't,
because it got decoded into "yes"/"no", both of which are true in
Perl.
[originally from svn r9617]
unconditionally set the telnet state to SEENCR regardless of whether
we have actually seen a CR, and as a result sending a NUL through
PuTTY (via Ctrl-Space or whatever) does not work. Must have arisen
through some kind of really weird cut-and-paste error!
[originally from svn r9545]
interpretation with some analysis done on it. The script will do its
own tracking of the set of open channels and their states, and its
output is in a one-line-per-packet format such that every distinct
channel has a unique identifier in it which should make it easy to
grep out all lines relating to that channel. The script also matches
up {CHANNEL,REQUEST}_{SUCCESS,FAILURE} to the requests that caused
them, by tracking a queue of requests in each direction per channel
and for global requests. Command-line options permit generating a
final dump of all channels ever known to the script and their various
ids and final state, and also dumping out the data transferred over
each channel in each direction.
Output is not complete, in the sense that some parameters in some
messages (e.g. pixel sizes in window-size specifications) are
deliberately omitted due to being boring, and the entire contents of
some messages (e.g. KEXINIT) are omitted because I haven't yet seen
any purpose in decoding them. Filling them in might be a useful thing,
although I'm inclined to think that the default should still be to
show only the potentially interesting stuff (e.g. still not pixel
sizes!) and enable the rest using a -v option.
Hopefully this should do a lot of the legwork in debugging issues in
which a channel mysteriously remains partially open and prevents PuTTY
closing.
[originally from svn r9457]
discussed. Use Barrett and Silverman's convention of "SSH-1" for SSH protocol
version 1 and "SSH-2" for protocol 2 ("SSH1"/"SSH2" refer to ssh.com
implementations in this scheme). <http://www.snailbook.com/terms.html>
[originally from svn r5480]