There was no way to enable it for testing purposes at all until now.
Overriding the server KEX string to mention it doesn't help when it
was prevented from getting into the list that scan_kexinit_lists will
go through afterwards to find pointers to algorithm structures.
Uppity is not secure enough to listen on a TCP port as if it was a
normal SSH server. Until now, I've been using it by means of a local
proxy command, i.e. PuTTY invokes Uppity in the same way it might
invoke 'plink -nc'. This rigorously prevents any hostile user from
connecting to my utterly insecure test server, but it's a thundering
inconvenience as soon as you want to attach a debugger to the Uppity
process itself - you have to stick a gdbserver somewhere in the middle
of your already complicated shell pipeline, and then find a way to
connect back to it from a gdb in a terminal window.
So I've added an option to make Uppity listen on a TCP port in the
normal way - but it's protected using that /proc/net/tcp trick I just
added in the previous commit.
This is a Linux-specific trick that I'm quite fond of: I've used it
before in 'agedu' and a lot of my unpublished personal scriptery.
Suppose you want to run a listening network server in such a way that
it can only accept connections from processes under your own control.
Often it's not convenient to do this by adding an authentication step
to the protocol itself (either because the password management gets
hairy or because the protocol is already well defined). The 'right'
answer is to switch from TCP to Unix-domain sockets, because then you
can use the file permissions on the path leading to the socket inode
to ensure that no other user id can connect to it - but that's often
inconvenient as well, because if any _client_ of the server is not
already prepared to speak AF_UNIX your control then you can only trick
it into connecting to an AF_UNIX socket instead of TCP by applying a
downstream patch or resorting to LD_PRELOAD shenanigans.
But on Linux, there's an alternative shenanigan available, in the form
of /proc/net/tcp (or tcp6), which lists every currently active TCP
endpoint known to the kernel, and for each one, lists an owning uid.
Listen on localhost only. Then, when a connection comes in, look up
the far end of it in that file and see if the owning uid is the right
one!
I've always vaguely wondered if there would be uses for this trick in
PuTTY. One potentially useful one might be to protect the listening
sockets created by local-to-remote port forwarding. But for the
moment, I'm only planning to use it for a less security-critical
purpose, which will appear in the next commit.
The very first thing I tried to test with the new KEXINIT override was
to select a non-default cipher in only one of the two connection
directions. It failed because both client and server tried to send AES
and receive ChaCha20, which doesn't work very well!
The server-readiness tweaks in ssh2transport.c included a switching
system so that when we scan both KEXINITs to determine the chosen
cipher, we can change which one we think is client and which is
server. But I'd forgotten to put in a similar switch for the
structures into which we put the selected algorithms for
client->server and server->client directions. Ahem.
This is an obviously useful test feature, since if nothing else it
will let me exercise every individual crypto primitive, even the ones
that the client-side configuration is too coarse-grained to describe
in detail (such as the difference between CBC and CTR mode versions of
the same cipher).
This mimics a bug in some old SSH servers for which PuTTY contains
compensation code (parsing an incoming "exit-signal" two ways and
seeing which one worked). I completely rewrote that code in commit
7535f645a, as part of the BinarySource rework. Now I can finally test
it sensibly.
Replaces a couple of existing strcmp, and does just slightly better
because as well as matching "--verbose" (say) it also matches
"--verbose=foo" and gives a comprehensible error message about it.
Re-consider the icon in light of the font size, so that we pick the icon
whose size mostly closely matches the terminal font, rather than always
scaling the default icon.
I've had to test banner handling several times recently, what with
trust sigils and the fix for CONF_ssh_show_banner. So it's the thing
I've most wanted to keep reconfiguring about Uppity so far.
This is much simpler than Conf, because I don't expect to have to copy
it around, load or save it to disk (or the Windows registry), or
serialise it between processes. So it can be a straightforward struct.
As yet there's nothing actually _in_ it. I've just created the
structure and arranged to pass it through to all the SSH layers. But
now it's here, it will be a place I can add configuration items as I
find I need them.
I'm going to want this in a moment for Uppity, and it seems like the
sort of thing I should put straight into utils.c now, rather than
having to move it over later when I inevitably find another use for
it.
Rather than insisting on allocating a string buffer the way fgetline
does, it reads a whole file and transfers the result into an arbitrary
BinarySink, which works out the same if you use a strbuf at the call
site, but can do other things too if that turns out useful.
Those two flags had the opposite sense to what you might expect: each
one is the value of the Conf entry corresponding to the checkbox that
_disables_ the corresponding terminal feature. So term->bidi is true
if and only if bidi is _off_.
I think that confusion of naming probably contributed to the control-
flow error fixed in the previous commit, just by increasing cognitive
load until I couldn't remember which flags were set where any more! So
now I've renamed the two fields of Terminal, and the corresponding
Conf keywords, to be called "no_bidi" and "no_arabicshaping", in line
with other 'disable this feature' flags, so that it's clear what the
sense should be.
The bidi algorithm is called on the array term->wcFrom, modifying it
in place. Then the Arabic-shaping algorithm - which can't work in
place because it needs to check the original value of array entries
it's already modified - is called, copying term->wcFrom to term->wcTo
as a side effect. Then the cleanup code expects the final version of
the line to be in wcTo. So if shaping is turned off, we still need to
copy wcFrom into wcTo, even if we don't modify it en route.
Previously, that copy was done under an if statement whose condition
boils down to 'if bidi is enabled but shaping is not'. So if that code
was ever reached with _both_ bidi and shaping turned off, then nothing
at all would copy wcFrom into wcTo, and wcTo would be filled with
nonsense.
Before trust sigils were introduced, that was OK, because the whole
function body was skipped if both bidi and shaping were turned off.
But now trust-sigil handling lives in there too, so we can get into
that code with the previously disallowed combination of flags. If
you're lucky, this means that the assert(opos == term->cols) near the
bottom of the function fails, on the basis that opos is the sum of
nonsense values from wcTo; if you're unlucky I suppose you might
manage to get _plausible_ nonsense through to the screen.
Now fixed, by changing that central if statement into a much more
obvious one: if we're running do_shape, then that can copy wcFrom into
wcTo, and if and only if we're _not_, then we must copy it another
way. (And while I'm here, I've turned that other way from a manual for
loop into memcpy.)
For ages, when rebuilding the configure script, I've had the
mysterious warning "configure.ac:120: warning: macro 'AM_PATH_GTK' not
found in library". The reason it was mysterious was that that use of
AM_PATH_GTK was inside an ifdef that checked whether it was defined,
and it actually wasn't being run!
Turns out the warning comes from 'aclocal', which is a Perl script
that (among other things) does bodgy text-matching to detect
unsupported autoconf/automake macros in your configure script. The
warning comes from the function scan_configure_dep() in that file, as
of aclocal-1.15. And, indeed, it ignores the ifdef structure, so it
doesn't notice that I've carefully guarded the use of that possibly-
undefined macro! (Though a comment in aclocal does acknowledge the
possibility, which is why it's only a warning.)
Against that bodgy and unreliable check, I've deployed an equally
bodgy and unreliable countermeasure, by changing the line spacing so
that AM_PATH_GTK appears in a context (specifically, not immediately
following a newline or space) where the regex will be confident that
it's a macro invocation. So that should squelch the warning.
glob.h is another missing facility in Android+Termux.
The workaround is to condition out local wildcard support completely,
so that PSFTP commands like 'mput *.txt' won't manage to do anything.
But at least the program will compile.
Test-building inside Termux on Android, it seems that <pwd.h> in that
environment defines the important functions getpwnam and getpwuid, but
not the setpwent/endpwent with which we bookend them. Tolerate their
absence.
uClibc-ng does not provide <sys/auxv.h>, and a non-Linux-kernel-based
Unixlike system running on Arm will probably not provide
<asm/hwcap.h>. Now we check for both of those headers at autoconf
time, and if either one is absent, we don't do the runtime test for
Arm crypto acceleration.
This should only make a difference on systems where this module
previously failed to compile at all. But obviously it would be nicer
to find alternative ways to check for crypto acceleration on such
systems; patches welcome.
Not every system provides it (e.g. uClibc-ng); if one does not, the
Uppity SFTP server should now degrade sensibly to refusing attempts to
set the utimes on an already-open file.
Baruch Siach reports that in a uClibc-ng build environment, POLLRDNORM
and friends are only defined by poll.h if you #define _XOPEN_SOURCE
before including it. So now we do that, in case it helps - and we also
cope with those #defines still being absent, in case on some other
system even that doesn't help.
Remove the 'winhelp-topic' IDs from the Halibut source, and from the
code. Now we have one fewer name to think of every time we add a
setting.
I've left the HELPCTX system in place, with the vague notion that it
might be a useful layer of indirection for some future help system on a
platform like Mac OS X.
(I've left the putty.hlp target in doc/Makefile, if nothing else because
this is a convenient test case for Halibut's WinHelp support. But the
resulting help file will no longer support context help.)
This is a fairly shallow patch, which removes the UI and interactions
with external libraries. Some other machinery (which is dead code in
this configuration) is left in place.
Adapted by me from a patch by Jeroen Roovers.
In particular, a report today pointed out that the call to
pfl_terminate(pfr->local) directly from portfwdmgr_config() was then
repeated from inside pfr_free(pfr) which we called four lines later,
leading to a double-free crash. Now we null out pfr->local the first
time, so the call in pfr_free is skipped.
While I'm at it, I've nulled out pfr->remote similarly; that doesn't
cause any crash that I can see, but it's a good habit to get into for
futureproofing.
We can only get fingerprints compatible with our own system by passing
the '-E md5' option to ssh-keygen. Also, we must strip the "MD5:"
prefix from the hash component of the returned fingerprint.
Since that hash appears in the middle of the string we were previously
extracting, I've reworked the whole cleanup_fp function to use the new
ptrlen_get_word, which makes it easy to extract two words from the
string and then strip a prefix off the second one.
This prevents an assertion failure when random_ref() tries to create
a new PRNG instance and finds there already is one. It also exposes
bugs in which some code path forgot to initialise the PRNG when it
was going to need it, such as the one fixed in the previous commit.
This is similar to strtok, only it operates on a ptrlen. Therefore it
can be properly stateless, or rather, it stores its state by
overwriting the input ptrlen to point to a tail of its previous value.
Also in this commit I add a clarifying comment about when
ptrlen_{starts,ends}with will write through its 'tail' pointer.
Previously, if the testcrypt subprocess suffered any kind of crash or
assertion failure during a run of the Python-based test system, the
effect would be that ChildProcess.read_line() would get EOF, ignore
it, and silently return the empty string. Then it would carry on doing
that for the rest of the program, leading to a long string of error
reports in tests that were nowhere near the code that actually caused
the crash.
Now ChildProcess.read_line() detects EOF and raises an exception, so
that the test suite won't heedlessly carry on trying to do things once
it's noticed that its subprocess has gone away.
This is more fiddly than it sounds, however, because of the wrinkle
that sometimes that function can be called while a Python __del__
method is asking testcrypt to free something. If that happens, the
exception can't be propagated out of the __del__ (analogously to the
rule that it's a really terrible idea for C++ destructors to throw).
So you get an annoying warning message on standard error, and then the
next command sent to testcrypt will be back in the same position.
Worse still, this can also happen if testcrypt has _already_ crashed,
because the __del__ methods will still run.
To protect against _that_, ChildProcess caches the exception after
throwing it, and then each subsequent write_line() will rethrow it.
And __del__ catches and explicitly ignores the exception (to avoid the
annoying warning if Python has to do the same).
The combined result should be that if testcrypt crashes in normal
(non-__del__) context, we should get a single exception that
terminates the run cleanly without cascade failures, and whose
backtrace localises the problem to the actual operation that caused
the crash. If testcrypt crashes in __del__, we can't quite do that
well, but we can still terminate with an exception at the next
opportunity, avoiding multiple cascade failures.
Also in this commit, I've got rid of the try-finally in
cryptsuite.py's (trivial) main program.
Now we only run the final memory-leak check if we didn't already have
some other error to report, or some other exception that terminated
the process.
Also, we wait for the subprocess to terminate before returning control
to the shell, so that any last-minute complaints from Leak Sanitiser
appear before rather than after the shell prompt comes back.
While I'm here, I've also made check_return_status tolerate the case
in which the child process never got started at all. That way, if a
failure manages to occur before even getting _that_ far, there won't
be a cascade failure from check_return_status getting confused
afterwards.
My API for ECDH KEX doesn't provide a function to input the random
bytes from which the private key is derived, but conveniently, the
existing call to random_read() in ssh_ecdhkex_m_setup treats the
provided bytes in exactly the way that these test vectors expect.
One of these tests also exercises the 'reduction mod 2^255' case that
I just added.
I just spotted this requirement in RFC 7748. A _sensible_ Ed25519
public value is an integer less than p=2^255-19, but the transport
format allows encoding of numbers up to 2^256, and RFC 7748 has a
specific recommendation for what to do with overlarge ones: namely,
ignore the topmost bit if it is set (i.e. reduce mod 2^255), and deal
with the remaining 19 overlarge values by reducing mod p.
Apparently the purpose is to 'increase resistance to implementation
fingerprinting', so the lack of this step wasn't a serious
interoperability or security issue.
This gets rid of the magic constants we apply to the top and bottom
bytes of the random data to make the Curve25519 private DH value. Or
rather, one of the magic constants is completely gone (we can infer it
from curve->fieldBits), and the other is moved into the curve
structure instead of being hardwired into the private-key-inventing
function.
With this change, it will be easy to add the similar Curve448 kex
method, because it's now just a matter of adding the protocol names
and curve constants.
The centralisation I did in commit e3796cb77 introduced a foolish
sense error, in which I was supposed to be treating an unbracketed
colon in CONF_hostname as separating host name from a port-number-
shaped suffix if it _was_ the only one, and instead, accidentally did
so if it _wasn't_.
Thanks to Sean Kain for pointing out MS's web page listing all the
known _MSC_VER values and their translations.
To make it an easier and more mechanical process to update the list in
future, I've completely replaced our previous text for each version
with a straight paste of the exact string translations from that web
page (plus Sean Kain's extra value for VS2019, which isn't listed on
that page yet). That changes the exact wording of all the previous
translations, mostly cosmetically (although it also fixes the version
number for _MSC_VER=1912).
Since many of the new translations end with a version number in
parentheses, I've removed the parens around the following explicit
statement of _MSC_VER, so they don't look silly next to each other.
Commit d07d7d66f introduced this bug: I replaced a manually grown
string buffer with a strbuf, and failed to replicate the part where
after I'd finished appending wire data to the string I removed the
terminating \n. That string was used as the local file name, when
downloading in SCP mode using a wildcard, so you'd get lots of local
files whose names ended inconveniently in a newline character.
Fixed by terminating the loop before we push the \n on to the strbuf
in the first place.
GetDlgItemText_alloc is often used to get passwords from text fields,
so the memory should be freed and erased properly. Otherwise parts
of passwords might leak in memory.
Signed-off-by: Sven Strickroth <email@cs-ware.de>
In my eagerness to make sure we didn't _accidentally_ change the
seat's trust status back to trusted at any point, I forgot to do it on
purpose if a second SSH login phase is legitimately run in the same
terminal after the first session has ended.
According to POSIX, this can legally not be defined 'where the [...]
value is equal to or greater than the stated minimum, but where the
value can vary depending on the file to which it is applied'. So if
limits.h hasn't defined PIPE_BUF, we define it ourself to the stated
minimum, to wit, _POSIX_PIPE_BUF.
Apparently it is actually undefined by <limits.h> on GNU/Hurd: Debian
has been carrying this patch downstream for that reason.
I carefully tested commit 801ab68ea's rewrite of invent_firstbits in
every way I could think of to ensure that I really was generating two
values whose product was at least 'minproduct'. But unfortunately the
value of 'minproduct' itself was off by a factor of two, which made
the entire system pointless!
The new_priv_openssh method for ECDSA keys was trying to initialise
the key as if it was EdDSA, leading to an assertion failure at setup
time.
This is what I get for not having taken cryptsuite.py all the way to
testing every top-level signature algorithm.
Fill in all the function pointers for 3rd party Windows GSS DLLs, not
just some of them. These were missed out when GSS key exchange was added
in d515e4f1a3.