OpenVPN with Yubikey 4 and PIN code

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

Comments are closed.