I decided to try something different, to avoid having to substitute OpenVPN on the router.
Changing the configuration of the OpenVPN server, it is possible to use a custom script to perform the username/password verification. The custom verification script then uses oathtool to check the token.
oathtool is availalbe as openwrt package, but at the end I decided to compile it using a docker container.
The steps to be performed are the following:
1 - Compile oathtool for the target (in this case RT-AC68U)
2 - Configure OpenVPN via the Asuswrt-Merlin web interface
3 - Create the verify.sh shell script
4 - Create the script to modify the OpenVPN server configuration
5 - Copy files to the router
6 - Create your google authenticator secret
7 - Reboot router
Instruction to compile oathtool with docker:
Code:
# Pull the docker image and run the container with a shared folder in the host system
docker pull acrisliu/asuswrt-merlin-build
docker run -dt -v C:\path\to\your\transfer\folder:/mnt/transfer --name asuswrt-merlin-build acrisliu/asuswrt-merlin-build
# Open a shell in docker
docker exec -it asuswrt-merlin-build bash
# Setup the environment for my RT-AC68U
. /root/env/bcm-sdk.sh
export CC=arm-brcm-linux-uclibcgnueabi-gcc
#Compile oathtool
cd /usr/src
wget https://fossies.org/linux/privat/oath-toolkit-2.6.2.tar.gz
gunzip oath-toolkit-2.6.2.tar.gz
tar -xf oath-toolkit-2.6.2.tar
cd oath-toolkit-2.6.2
./configure --disable-xmltest --disable-pskc --host=armv7
make
# Copy oathtool executable to the transfer folder
In the router GUI go to VPN>VPN Server and enable the OpenVPN Server.
Make sure the following is set:
Code:
Username/Password Authentication = Yes
Autenticazione solo con Nome utente / Password = No
Export the Configuration for the client
I used the following script to verify the username/password provided.
Note that username/password list is available and readable in the nvram.
I stored a list of username/secret also in the same way in the nvram (see step 6)
verify.sh:
Code:
#!/bin/sh
#Location: /jffs/openvpn/verify.sh
#This script was made with via-file in mind
PATH=/usr/bin:/bin
#users/passwords
users=`/usr/sbin/nvram get vpn_serverx_clientlist`
users="$users<"
#users/secrets
secrets=`/usr/sbin/nvram get vpn_serverx_secretlist`
secrets="$secrets<"
#1st line is the username
username=`/usr/bin/awk 'NR==1' "$1"`
#2nd line is the password
password=`/usr/bin/awk 'NR==2' "$1"`
#username consist only of alphanumerics_-.@
if [[ `echo "$username" | sed 's/[0-9A-Za-z_\-\.@]*//'` ]];
then
echo "Invalid character in username." >&2
exit 1
fi
if echo "$password" | grep -q "<" ;
then
echo "Invalid character in password." >&2
exit 1
fi
if ! echo "$users" | grep -q "<$username>" ;
then
echo "Username invalid." >&2
exit 1
fi
if ! echo "$secrets" | grep -q "<$username>" ;
then
echo "Username has no secret." >&2
exit 1
fi
#get correct password and secret and code
pass=`echo "$users" | sed 's/^.*<'"$username"'>\([^<]*\)<.*$/\1/'`
secret=`echo "$secrets" | sed 's/^.*<'"$username"'>\([^<]*\)<.*$/\1/'`
code=`/jffs/openvpn/oathtool -b --totp "$secret"`
if [[ "$password" == "$pass$code" ]];
then
echo "$username User Authenticated."
exit 0
fi
echo "$username Login credentials failed." >&2
exit 1
Then the script to modify the configuration of OpenVPN
openvpnserver1.postconf:
Code:
#!/bin/sh
#Location: /jffs/scripts/openvpnserver1.postconf
CONFIG=$1
source /usr/sbin/helper.sh
pc_delete "plugin /usr/lib/openvpn-plugin-auth-pam.so openvpn" $CONFIG
pc_append "script-security 2" $CONFIG
pc_append "auth-user-pass-verify /jffs/openvpn/verify.sh via-file" $CONFIG
#pc_append "reneg-sec 60" $CONFIG
pc_append "auth-gen-token" $CONFIG
Copy files to the router:
Code:
scp oathtool admin@IP:/jffs/openvpn/oathtool
scp verify.sh admin@IP:/jffs/openvpn/verify.sh
scp openvpnserver1.postconf admin@IP:/jffs/scritps/openvpnserver1.postconf
chmod +x /jffs/openvpn/oathtool
chmod +x /jffs/openvpn/verify.sh
chmod +x /jffs/scritps/openvpnserver1.postconf
Create a Google Authenticator secret (base32) with any tool you want
Try it (should gave same result as your Google Authenticator or Authy App)
Code:
/jffs/openvpn/oathtool -b --totp YOURGASECRETHERE
nvram set "vpn_serverx_secretlist=<yourusername>YOURGASECRETHERE"
nvram commit
reboot the router
Once up, you can connect to the VPN using username and password and the token:
username=yourusername
password=yourpassword######
where ###### is the token appended to your password
I have to say, I am not an expert of shell scripts and any input to improve the verify.sh script are welcome, together with any comment or concern about security of the solution.
manovel