After buying a Yubikey 4, I wanted to see what this little sucker could do, besides being used as U2F two-factor thingy for Gmail and so on, so I found out it could be used as a smartcard, meaning I could save X.509/PEM keys and certificates inside it, which I again could use for my OpenVPN connections! Happiness was in my face, until I found out that OpenVPN and PKCS11 with PIN codes is currently somewhat broken on some systems (including my Ubuntu 16.04), as I need to enter the PIN via the OpenVPN Management interface due to some broken systemd-ask-password thing. This severely complicates my setup, as I usually just start the OpenVPN connection via the terminal by something like “sudo openvpn <configfile>” which was suddenly not possible, or at least I then needed to do a lot more… So after thinking (whoa) and googling some, I came up with this small bash script utilizing netcat and some piping to automate this whole shebang. The script requires that the OpenVPN client configuration has these lines:
auth-retry nointeract management 127.0.0.1 8888 management-query-passwords
So we start a management interface locally on port 8888 and query passwords here. The script then looks like this:
#!/bin/bash
USER=`whoami`
MGM_PORT=8888
if [ "$USER" != 'root' ]; then
echo "Must be run with superuser priviledges"
fi
if [ -z $1 ]; then
echo "Usage: $0 < vpn-config >"
exit 1
fi
printf "OpenVPN PKCS11 PIN wrapper\n"
read -s -p "Enter PIN: " PINCODE
printf "\nStarting OpenVPN\n"
/usr/sbin/openvpn $1 > /dev/null &
OPENVPN_PID=$!
# Give OpenVPN a chance to get somewhere
sleep 2
PIPE=/tmp/ovpn_pkcs11_fifo
trap "rm -f $PIPE" EXIT
if [[ ! -p $PIPE ]]; then
mkfifo $PIPE
fi
# Start nc with a 2 second delay
(sleep 2 && nc localhost $MGM_PORT) > $PIPE &
SUBSTRING=
while true
do
if read LINE < $PIPE; then
if [[ $LINE == *"PASSWORD"* ]]; then
SUBSTRING=$(echo $LINE | cut -d "'" -f 2)
break
fi
fi
done
echo "password '$SUBSTRING' '$PINCODE'" | nc localhost $MGM_PORT > /dev/null
printf "Write 'quit' to kill OpenVPN instance: "
while read LINE; do
if [ "$LINE" == "quit" ]; then
kill $OPENVPN_PID
exit 0
fi
done