Key signing parties are a
pain and hopefully, one day, we will have better ways to authentication keys
than reading hexadecimal strings out loud.
The
Zimmermann Sassaman key-signing
protocol
makes them much more bearable already by having only one single hexadecimal
string read out loud. That string is the cryptographic hash of a document
given to every participant listing all participants and their fingerprints.
If everyone has the same hash, then we assume that everyone has the same
document. Then, participants in turn will confirm that they fully recognize
the fingerprint listed in the document.
Alexander Wirt wrote a
small key
server dedicated to receive keys from
the participants. There is also a script that will generate the document from
the submitted keys and a ready-to-use keyring. The latter can be run
automatically using
inoticoming when a new key
arrives. Finally, it would be nice if participants could confirm that their key
has been properly added to the document, e.g. by making the list available on a
web server.
Setting all this up seemed like a good opportunity to play with
Tor hidden services and
systemd-nspawn.
Here's the setup log with some comments. This was done on a small
armhf
device with Debian Jessie.
Create a new hidden service
Edit
/etc/tor/torrc
on the host to setup the hidden service:
HiddenServiceDir /var/lib/tor/ksp/
HiddenServicePort 80 10.0.0.2:80
HiddenServicePort 11371 10.0.0.2:11371
Run:
host# systemctl reload tor.service
Then, to learn the name of the newly created hidden service name:
host# cat /var/lib/tor/ksp/hostname
ksp123456789abcd.onion
Install the container
debootstrap
as always:
host# debootstrap --variant=minbase jessie /var/lib/container/ksp
Preliminary container configuration
We do the following step simply using
chroot
as we are going to
use the host network configuration for this stage. The container itself will
not have access to the Internet.
host# chroot ksp
Let's set the hostname:
ksp-chroot# echo 'ksp' > /etc/hostname
Set up APT:
ksp-chroot# echo 'deb http://httpredir.debian.org/debian jessie main' > /etc/apt/sources.list
ksp-chroot# apt update
We need
dbus
to get systemd to work well:
ksp-chroot# apt-get install dbus
Make sure that we can resolve our own hostname:
ksp-chroot# apt-get install libnss-myhostname
ksp-chroot# sed -e '/^hosts:/s/files/myhostname \0/' -i /etc/nsswitch.conf
These are dependencies of the keyserver:
ksp-chroot# apt-get install --no-install-recommends libhttp-daemon-perl \
liblog-loglite-perl libproc-reliable-perl
These ones are needed for the script generating the list:
ksp-chroot# apt-get install bzip2 inoticoming
And we will use the smallest HTTP server available:
ksp-chroot# apt-get install netcat-traditional micro-httpd
Finally, let's unconfigure all DNS resolvers:
ksp-chroot# echo > /etc/resolv.conf
And we are done with the chroot:
ksp-chroot# exit
Let's retrieve the
ksp-tools
repository now:
host# cd /var/lib/container/srv
host# git clone https://github.com/formorer/ksp-tools
Container setup
We will now start the container with a shell to configure it:
host# systemd-nspawn -D ksp --network-veth
Let's ask systemd to configure the network for us:
ksp# systemctl enable systemd-networkd
Let's not forget to set a root password:
ksp# passwd
We add a dedicated user to run the keyserver and the list generation script:
ksp# adduser --system --group --disabled-password --disabled-login --home /var/lib/ksp ksp
Let's configure the keyserver:
ksp# cp /srv/ksp-tools/keyserver.conf /var/lib/ksp/keyserver.conf
Let's edit
/var/lib/ksp/keyserver.conf
:
homedir = /var/lib/ksp
Now create the GnuPG homedir for the keyserve:
ksp# mkdir /var/lib/ksp/keys
ksp# install -d -o ksp -g ksp -m 0700 /var/lib/ksp/keys/gpg
Copy the template list generator:
ksp# cp -r /srv/ksp-tools/example /var/lib/ksp/keys/ksp123456789abcd_onion
Create the key repository:
ksp# install -d -o ksp -g ksp -m 0700 /var/lib/ksp/keys/ksp123456789abcd_onion/keys
Create a directory accessible to the web server where the participant list will
be generated:
ksp# mkdir -p /var/www
ksp# install -d -o ksp -g ksp -m 0755 /var/www/keys
Let's configure the list generation script by editing
/var/lib/ksp/keys/ksp123456789abcd_onion/conf/vars
:
KS=ksp123456789abcd.onion
export GNUPGHOME=/tmp/ksp-gpg
KSPFILE="/var/www/keys/ksp-event.txt"
Don't forget to adjust the header in
/var/lib/ksp/keys/ksp123456789abcd_onion/conf/list-header
.
Now we create a unit file for the keyserver in
/etc/systemd/system/keyserver.service
:
[Unit]
Description=Key signing party keyserver
[Service]
Type=simple
Environment="KSP_HOMEDIR=/var/lib/ksp"
ExecStart=/srv/ksp-tools/bin/kspkeyserver.pl --nodaemonize
User=ksp
Group=ksp
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full
ReadOnlyDirectories=/
ReadWriteDirectories=-/var/lib/ksp
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
Another unit for the list generator as
/etc/systemd/system/ksp-list-generator.service
:
[Unit]
Description=Key signing party list generator
[Service]
Type=simple
EnvironmentFile=/var/lib/ksp/keys/ksp123456789abcd_onion/conf/vars
ExecStart=/usr/bin/inoticoming --foreground /var/lib/ksp/keys/ksp123456789abcd_onion/keys --chdir /var/lib/ksp/keys/ksp123456789abcd_onion bin/generate-list \;
User=ksp
Group=ksp
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full
ReadOnlyDirectories=/
ReadWriteDirectories=/var/www/keys
CapabilityBoundingSet=
[Install]
WantedBy=multi-user.target
For the web server, we first configure a socket listening on port 80 in
/etc/systemd/system/micro-httpd.socket
:
[Unit]
Description=micro-httpd socket
[Socket]
ListenStream=80
Accept=yes
[Install]
WantedBy=sockets.target
And then the web server in
/etc/systemd/system/micro-httpd@.service
:
[Unit]
Description=micro-httpd server
[Service]
ExecStart=-/usr/sbin/micro-httpd /var/www/ksp
StandardInput=socket
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full
ReadOnlyDirectories=/
CapabilityBoundingSet=
Let's now ask systemd to start all of these at boot time:
ksp# systemctl daemon-reload
ksp# systemctl enable keyserver.service
ksp# systemctl enable ksp-list-generator.service
ksp# systemctl enable micro-httpd.socket
One way to kill the container is to type Control+
]
three times.
Boot the container
Let's get this party started!
host# systemd-nspawn -b -D /var/lib/container/ksp --network-veth
Hopefully, things should work now. Participants to the KSP should then be able
to send their key with:
$ torsocks gpg --keyserver ksp123456789abcd.onion --send-key $KEYID
(Sadly, this is
broken with GnuPG
2.1 at the
moment.)
The participant list should be available at
http://ksp123456789abcd.onion/ksp-event.txt
.
Final steps
We need to tell systemd to start the container started at boot time:
host# systemctl enable systemd-nspawn@ksp.service
But the default command-line will not use a dedicated network, so we need
to override that part of the configuration. First create a directory:
host# mkdir /etc/systemd/system/systemd-nspawn@ksp.service.d
And edit
/etc/systemd/system/systemd-nspawn@ksp.service.d/use-network-veth.conf
:
[Service]
# The empty line because we want to override all previous ExecStart
# and not add an extra command
ExecStart=
ExecStart=/usr/bin/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --directory=/var/lib/container/%i --network-veth
Let's reload systemd and verify that our snippet is there:
host# systemctl daemon-reload
host# systemctl cat systemd-nspawn@ksp.service
All good? Let's start it:
host# systemctl start systemd-nspawn@ksp.service
One should also add a firewall to disallow any outgoing connections from the
ve-ksp
interface as an extra protection.