Delays on bad passwords considered harmful, accidental reboot edition
Here is what I just did to myself, in transcript form:
$ /bin/su Password: <type> [delay...] ['oh, I must have mistyped the password'] [up-arrow CR to repeat the su] bash# reboot <CR>
The normal root shell is bash and it had a bash history file with
'reboot' as the most recent command. When my
su invocation didn't drop
me into a root shell immediately I assumed that I'd fumbled the password
and it was forcing a retry delay (as almost all systems are configured
to do). These retry delays have trained me so that practically any time
su stalls on a normal machine I just repeat the
su; in a regular
shell session this is through my shell's interactive history mechanism
with an up-arrow and a CR, which I can type ahead before the shell
prompt reappears (and so I do).
Except this time around
su had succeeded and either the machine or the
network path to it was slow enough that it had just looked like it had
failed, so my 'up-arrow CR' sequence was handled by the just started
bash and was interpreted as 'pull the last command out of history
and repeat it'. That last command happened to be a 'reboot', because I'd
done that to the machine relatively recently.
(The irony here is that following my own advice I'd turned the delay off on this machine. But we have so many others with the delay on that I've gotten thoroughly trained in what to do on a delay.)
Using the SSH protocol as a secure transport protocol
I have an IPSec problem: my IPSec tunnel uses constant keys, with no periodic automatic rekeying. While IPSec has an entire protocol to deal with this called IKE, in practice IKE daemons (at least on Linux) are such a swamp to wade into that I haven't been willing to spend that much time on it. Recently I had a realization; rather that wrestle with IKE, I could just write a special purpose daemon to rekey the tunnel for me. Since both ends of the IPSec tunnel need to know the same set of keys, I need to run the daemon at either end and the ends have to talk to each other. Since they'll be passing keys back and forth, this conversation needs to be encrypted and authenticated.
The go-to protocol for encryption and authentication is TLS. But TLS has a little problem for my particular needs here in that it very much wants to do authentication through certificate authorities. I very much don't want to. The two endpoints are fixed and so are their authentication keys, and I don't want to have to make up a CA to sign two certificates and (among other things) leave myself open to this CA someday signing a third key. In theory TLS can be used with direct verification of certificate identities, but in practice TLS libraries generally make this either hard or impossible depending on their APIs.
As I was thinking about this it occurred to me that there is already a secure transport protocol that does authentication exactly the way I want it to work: SSH. SSH host keys and SSH public key authentication is fundamentally based on known public keys, not on CAs. I don't want to literally run my rekeying over SSH for various reasons (including security), but these days many language environments have SSH libraries with support for both the server and client sides. The SSH protocol even has 'do command' operation that can be naturally used to send operations to a server, get responses, and perhaps supply additional input.
It's probably a little bit odd to use SSH as a secure transport protocol for your own higher level operations that have nothing to do with SSH's original purpose. But on the other hand, why not? If the protocol fits my needs, I figure that I might as well be flexible and repurpose it for this.
(The drawback is that SSH is relatively complex at the secure transport layer if all that you want is to send some text back and forth. Hopefully the actual code complexity will be minimal.)