How I Setup My OpenVPN

Edited: As mentioned by @JW0914, the documentation that was used to do this write-up has a number of security vulnerabilities which the proper remediation are discussed at the bottom of this posting.

Hello Community,

I have noticed there were a lot of people who were experiencing the same issues I had when trying to configure my Linksys WRT 3200acm router as an OpenVPN server.

some of the articles I used as reference were the following

I was working on OpenWRT/LEDE 18 version found here.

I was following the number of how-to manuals from communities and the OpenWRT's site. I tried the RSA method which gave me some issues with certificate validations and I read that easyrsa was not the most secure of methods. So in the end the procedures that worked for me was here.

OpenVPN Setup Guide for Beginners
Authentication with username and password

The directions were a bit confusing at first and luckily I powered through it and I was able to get it working. In turn, I felt I should contribute to the community to provide the steps and procedures I used based off of the above guides. If this is not the proper use of the forum or I am not following proper protocol with this post, please let me know and I will make the changes necessary to abide by LEDE Project Forum standards and guidelines.

Another reason I wanted to do this write up was to have the community review it and provide their feedback.

I followed the OpenSSL commands since it was labeled as the "most secure".

  1. update and install openvpn (the image I had, already had openvpn on it so I did not need to do this step).
opkg update; opkg install openvpn-openssl openvpn-easy-rsa
  1. I followed the guide and setup all my variables, created the index.txt file, created folders, and set permissions. These were all commands entered on the command line as root.
PKI_DIR="/etc/openvpn/ssl"
echo ${PKI_DIR}
rm -r ${PKI_DIR}
mkdir -p ${PKI_DIR}
ls -larth ${PKI_DIR}
chmod -R 0600 ${PKI_DIR}
cd ${PKI_DIR}
ls
touch index.txt; echo 1000 > serial
mkdir newcerts # certs crl csr private
  1. I then copied the openssl.cnf file to the directory just created as a reference.
cp /etc/ssl/openssl.cnf ${PKI_DIR}
ls
  1. I created another variable that points to the .cnf file.
PKI_CNF=${PKI_DIR}/openssl.cnf
  1. I then copied and pasted the following lines into the command line (before blindly copying and pasting the commands below, I went into the file using the "vi" command i.e. vi ${PKI_CNF} to see what items these "sed" commands would be searching and replacing).
sed -i '/^dir/   s:=.*:= /etc/openvpn/ssl:'                      ${PKI_CNF}
sed -i '/.*Name/ s:= match:= optional:'                    ${PKI_CNF}
sed -i '/organizationName_default/    s:= .*:= Anon:'  ${PKI_CNF}
sed -i '/stateOrProvinceName_default/ s:= .*:= Hawaii:'    ${PKI_CNF}
sed -i '/countryName_default/         s:= .*:= US:'        ${PKI_CNF}
sed -i '/default_days/   s:=.*:= 3650:'                    ${PKI_CNF} ## default usu.: -days 365 
sed -i '/default_bits/   s:=.*:= 4096:'                    ${PKI_CNF} ## default usu.: -newkey rsa:2048
sed -i '/default_md/     s:=.*:= default:'                 ${PKI_CNF} ## default usu.: sha256
  1. I then appended the same file with the additional configurations.
cat >> ${PKI_CNF} <<"EOF"
###############################################################################
### Check via: openssl x509 -text -noout -in *.crt | grep 509 -A 1
[ my-server ] 
#  X509v3 Key Usage:          Digital Signature, Key Encipherment
#  X509v3 Extended Key Usage: TLS Web Server Authentication
  keyUsage = digitalSignature, keyEncipherment
  extendedKeyUsage = serverAuth
[ my-client ] 
#  X509v3 Key Usage:          Digital Signature
#  X509v3 Extended Key Usage: TLS Web Client Authentication
  keyUsage = digitalSignature
  extendedKeyUsage = clientAuth
EOF
  1. I then created the certificates as stated in the OpenWRT documentation. I was confused about the #comments and then realized that the author was making the comparison to easyrsa commands that performed the equivalent.
openssl req -batch -nodes -new -keyout "ca.key" -out "ca.crt" -x509 -config ${PKI_CNF}  ## x509 (self-signed) for the CA
openssl req -batch -nodes -new -keyout "my-server.key" -out "my-server.csr" -subj "/CN=my-server" -config ${PKI_CNF}
openssl ca  -batch -keyfile "ca.key" -cert "ca.crt" -in "my-server.csr" -out "my-server.crt" -config ${PKI_CNF} -extensions my-server
openssl req -batch -nodes -new -keyout "my-client.key" -out "my-client.csr" -subj "/CN=my-client" -config ${PKI_CNF}
openssl ca  -batch -keyfile "ca.key" -cert "ca.crt" -in "my-client.csr" -out "my-client.crt" -config ${PKI_CNF} -extensions my-client
  1. I then configured the certs' permissions and verified them:
chmod 0600 "ca.key"
chmod 0600 "my-server.key"
chmod 0600 "my-client.key"
ls -larth ca.key 
ls -larth my-server.key 
ls -larth my-client.key 
  1. this cert was a big one but luckly the Linksys WRT 3200acm processor was faster when generating this one.
openssl dhparam -out dh2048.pem 2048     ## equivalent to the 'build-dh' script
  1. in this command, the author was trying to speak on checking what would be backed up if the user was to run the backup config command.
sysupgrade -l | grep rsa

The output will display what items would be backed up when your run the backup command.

/etc/dropbear/dropbear_rsa_host_key
/etc/easy-rsa/pki/.rnd
/etc/easy-rsa/pki/ca.crt
/etc/easy-rsa/pki/certs_by_serial/01.pem
/etc/easy-rsa/pki/dh.pem
/etc/easy-rsa/pki/index.txt
/etc/easy-rsa/pki/index.txt.attr
/etc/easy-rsa/pki/index.txt.old
/etc/easy-rsa/pki/issued/vpnserver.crt
/etc/easy-rsa/pki/private/ca.key
/etc/easy-rsa/pki/private/vpnserver.key
/etc/easy-rsa/pki/reqs/vpnserver.req
/etc/easy-rsa/pki/serial
/etc/easy-rsa/pki/serial.old
/etc/easy-rsa/pki/ta.key
/etc/easy-rsa/vars

This will help the end user determine what needs to be backed up or added to the back up list. If the output does not match what is listed above, add the items with the following command and confirm it was updated:

echo ${PKI_DIR}/*     > /lib/upgrade/keep.d/my-pki
sysupgrade -l | grep rsa
  1. Next step is to create the .ovpn profile that are files to be distributed to your clients devices i.e. mobile devices, computers, etc. To start, create the following variable from the command line.
OVPN_FILE="/etc/openvpn/unitelife.ovpn"
  1. copy and paste the following string into the command line:
    Important notice: it would be best to use a static ip (if your isp provider account is setup for this) but my isp is dhcp based. If it is dhcp, I highly recommend duckdns.org as they are a free service, they have great documentation on how to install the auto update api to your domain when your ip changes, and the new image of OpenWRT/LEDE has the DDNS service preinstalled.
    Note: the "cat" commands at the end refer to the certs and key files created in steps 7 and 8 (make sure to be in the same directory as the cert and keys when executing this command or "<" to the full/path/to/file.crt ).
tee /etc/openvpn/unitelife.ovpn >/dev/null <<EOF2
client     ## implies pull, tls-client
dev tun
proto udp  ## udp is the default
fast-io
remote your-domain-at.duckdns.org 1194
remote-cert-tls server
nobind
persist-key
persist-tun
comp-lzo no
verb 3
EOF2
echo '<ca>'    >> ${OVPN_FILE}
cat            >> ${OVPN_FILE} < ca.crt        
echo '</ca>'   >> ${OVPN_FILE}

echo '<cert>'  >> ${OVPN_FILE}
cat            >> ${OVPN_FILE} < my-client.crt 
echo '</cert>' >> ${OVPN_FILE}

echo '<key>'   >> ${OVPN_FILE}
cat            >> ${OVPN_FILE} < my-client.key 
echo '</key>'  >> ${OVPN_FILE}
  1. export the file with a tool like winscp set to "scp" file protocol set. If you are *nix based OS the the following commands should work:
ssh -y root@192.168.1.234 'mkdir -p /etc/openvpn'
scp ${OVPN_FILE} root@192.168.1.234:/etc/openvp #replace 192.168.1.234 with the ip address of the device the .ovpn file will be uploaded/downloaded to for distribution
cp /etc/openvpn/ssl/ca.crt /etc/openvpn/ssl/my-server.* /etc/openvpn/ssl/dh2048.pem /etc/openvpn
scp /etc/openvpn/ssl/ca.crt /etc/openvpn/ssl/my-client.* root@CLIENT_IP_ADDRESS:/etc/openvpn
  1. The steps from the OpenWRT site used the "uci" command to configure the openvpn server config file. I preferred to manually type it in the server config file because "uci" would wipe out previous configurations that may exist in the file.
vi /etc/config/openvpn

Review the following configs, make changes to meet your use-case, etc. I decided to use the tunnel method v.s. the tap.

Note: Please keep in mind the following options within the file under config option script_security '2' and option auth_user_pass_verify '/bin/openvpn-auth.sh via-file' I will reference this difference from the OpenWRT playbook later in this document. In addition, notice the similar referrences to the keys and certs created from steps 7 and 8.

config openvpn 'vpnserver'
        option enabled '1'
        option verb '3'
        option port '1194'
        option proto 'udp'
        option dev_type 'tun'
        option dev 'ovpns0'
        option server '192.168.200.0 255.255.255.0'
        option keepalive '10 120'
        option ca '/etc/openvpn/ca.crt'
        option cert '/etc/openvpn/my-server.crt'
        option key '/etc/openvpn/my-server.key'
        option dh '/etc/openvpn/dh2048.pem'
        list push 'route 192.168.0.0 255.255.255.0'
        list push 'dhcp-option DNS 192.168.0.1'
        list push 'redirect-gateway def1'
        option tun_mtu '1500'
        option topology 'subnet'
        option route_gateway 'dhcp'
        option log '/tmp/openvpn.log'
        option client_to_client '1'
        option persist_key '1'
        option persist_tun '1'
        option mode 'server'
        option script_security '2'
        option auth_user_pass_verify '/bin/openvpn-auth.sh via-file'        

The following instructions is what I included to the .ovpn file to include password authentication to prompt the end-users/clients to input their credentials before connecting to the network. The OpenWRT instructions made it so that the .ovpn file will automatically connect the client to the network. The security-side in me didn't like this, in the event that some badies got a hold of my .ovpn profile and exploited my network.

  1. Open the .ovpn file in a text editor on the device you exported the .ovpn file from the router i.e. notepad, vi, nano, notepad++, etc. and add the following
auth-user-pass
auth-nocache

The .ovpn file should finally look similar to this:

client     ## implies pull, tls-client
dev tun
proto udp  ## udp is the default
fast-io
remote your-domain-at.duckdns.org 1194
remote-cert-tls server
nobind
persist-key
persist-tun
verb 3
key-direction 1
redirect-gateway def1
auth-user-pass
auth-nocache
<ca>
-----BEGIN CERTIFICATE-----
MIIFLTCCAxWgAwIBAgIJAJg0Oxj7Wdj ... <EXCERPT> ...
-----END CERTIFICATE-----
</ca>
<cert>
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 4097 (0x1001)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=CU, ST=State, O=Anon
        Validity
            Not Before: Jun 23 07:01:28 2018 GMT
            Not After : Jun 20 07:01:28 2028 GMT
        Subject: CN=my-client
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    00:cc:ec:f9:92:cc:5a:be:5d:81:14:bd:78:62:8a:
                    .... <EXCERPT> ...
                    27:0a:23:11:6c:d3:bc:5f:67:af:2b:54:0a:6b:a8:
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: 
                Digital Signature
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
    Signature Algorithm: sha256WithRSAEncryption
         8c:46:25:46:fc:71:ee:47:b9:9a:ff:bb:1b:d3:d6:dd:09:44:
         ..... <EXCERPT> ....
         52:5a:5c:2f:cc:69:e5:83
-----BEGIN CERTIFICATE-----
MIIE4TCCAsmgAwIBAgICEAEwDQYJK... <EXCERPT>
-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN PRIVATE KEY-----
MIIJQwIBADANBgkqhkiG9w0BAQEFAA... <EXCERPT>
-----END PRIVATE KEY-----
</key>
  1. The following script creates a username and password. The script hashes the password and stores it in a file to referrence by another script we named openvpn-auth.sh. This script was mentioned in step 14 under the openVPN server config file under the option script_security '2' and option auth_user_pass_verify '/bin/openvpn-auth.sh via-file' syntax.
vi /etc/openvpn/createvpnuser.sh

copy and paste the following:
Note: Keep in mind the output file referenced at the end of this createvpnuser.sh script, auth. this is the file the authentication script will use to check the existence of the client/end-user.

#!/bin/sh
#genhash.sh
#Generate Hash for username/password
#Case sensitive and only allows a certain set of characters to be used

function hashround() {
    local hash rest
    read hash rest
    printf '%s%s' "$hash" "$hash" | /usr/bin/md5sum
}

case "$1" in *[!-_a-zA-Z0-9]*) exit 1 ;; esac
case "$2" in *[!-_a-zA-Z0-9]*) exit 1 ;; esac

hashpass=$(printf '%s%s' "$1" "$2" | /usr/bin/md5sum \
           | hashround | hashround | hashround | hashround | hashround \
           | hashround | hashround | hashround | hashround | hashround \
           | /usr/bin/cut -d' ' -f1)

echo "Username: $1"
echo "Password: $2"
echo "Password (MD5 Hashed): $hashpass"

echo "User added to approved user file"
echo "$1:$hashpass" >> /etc/openvpn/auth
  1. Create your user account and password. The password is rudimentary at best as the script only allows letters, numbers, "-", "_", etc. and no special characters.
./createvpnuser.sh <username> <password>

Verify the user and the hash equivalent of the password was created

cat /etc/openvpn/auth

Output should be similar to the following:

unitelife:92s8e2yDn8sET620fa9f7f1427bd0e5s
  1. Create the username and password authentication script.
    Notice the users="/etc/openvpn/auth" referenced.
#!/bin/sh
#verify.sh
#This script was made with via-file in mind

PATH=/usr/bin:/bin

#Function used for generating MD5 hash value of password multiple times
function hashround() {
    local hash rest
    read hash rest
    printf '%s%s' "$hash" "$hash" | /usr/bin/md5sum
}

#Location of the Approved Username/Password File
users="/etc/openvpn/auth"

#Check to see if generated OpenVPN login file has any special characters
#Terminate script if special characters are used
if /bin/grep -q '[^-_a-zA-Z0-9]' "$1"
then
        echo "Illegal characters found in username/password." >&2
        exit 1
fi

#1st line is the username
username=`/usr/bin/awk 'NR==1' "$1"`
#2nd line is the password
password=`/usr/bin/awk 'NR==2' "$1"`

#Generate MD5 hash of given password and loop it 10 times before comparing with hash value in users file
hashpass=$(printf '%s%s' "$username" "$password" | /usr/bin/md5sum \
           | hashround | hashround | hashround | hashround | hashround \
           | hashround | hashround | hashround | hashround | hashround \
           | /usr/bin/cut -d' ' -f1)

if /bin/grep -Fxq "$username:$hashpass" "$users"
then
        echo "User Authenticated." >&2
        exit 0
fi

echo "Login credentials failed." >&2
exit 1
  1. Now we can test the .ovpn connection on a clients machine. Check the logs to see if any errors appear.
tail -f /tmp/openvpn.log

If all is well, the output should reflect the following:

Tue Jun 26 01:14:32 2018 172.56.44.236:36052 peer info: IV_GUI_VER=OpenVPN_GUI_11
User Authenticated.
Tue Jun 26 01:14:32 2018 172.56.44.236:36052 TLS: Username/Password authentication succeeded for username 'unitelife'
Tue Jun 26 01:14:32 2018 172.56.44.236:36052 WARNING: 'keydir' is present in remote config but missing in local config, remote='keydir 1'
Tue Jun 26 01:14:33 2018 172.56.44.236:36052 Control Channel: TLSv1.2, cipher TLSv1/SSLv3 ECDHE-RSA-AES256-GCM-SHA384, 4096 bit RSA
Tue Jun 26 01:14:33 2018 172.56.44.236:36052 [my-client] Peer Connection Initiated with [AF_INET]172.56.44.236:36052
Tue Jun 26 01:14:33 2018 my-client/172.56.44.236:36052 MULTI_sva: pool returned IPv4=192.168.200.2, IPv6=(Not enabled)
Tue Jun 26 01:14:33 2018 my-client/172.56.44.236:36052 MULTI: Learn: 192.168.200.2 -> my-client/172.56.44.236:36052
Tue Jun 26 01:14:33 2018 my-client/172.56.44.236:36052 MULTI: primary virtual IP for my-client/172.56.44.236:36052: 192.168.200.2
Tue Jun 26 01:14:34 2018 my-client/172.56.44.236:36052 PUSH: Received control message: 'PUSH_REQUEST'
Tue Jun 26 01:14:34 2018 my-client/172.56.44.236:36052 SENT CONTROL [my-client]: 'PUSH_REPLY,route 192.168.0.0 255.255.255.0,dhcp-option DNS
Tue Jun 26 01:14:34 2018 my-client/172.56.44.236:36052 Data Channel: using negotiated cipher 'AES-256-GCM'

And that is pretty much what it took to get my vpn up and running. Please feel free to leave any feedback, comments, remarks to help improve or correct any configurations I may have done or best practices that should be followed.

Sincerely,

A humbly committed student

First and foremost, you should be commended for spending a substantial amount of time on your project and wanting to contribute your knowledge. With that being said, I'm a bit lost on what exactly the purpose of most of this thread is, as you essentially wrote a wiki that already has two wikis which fully address OpenVPN Server Setup on OpenWrt [OpenVPN (Server Setup) & OpenVPN Server (Comprehensive)].

  • Whether your intended to or not, you essentially plagiarized from the OpenVPN (Server Setup) Wiki (you literally copied and pasted the content from that wiki into yours).

There's a whole host of issues with your write up, of which are covered in the the aforementioned wikis.

  • You've created a security issue by attempting to implement auth-user-pass, of which should only be implemented on a system that has the appropriate OpenVPN plugin [*.so ], else the passwords will be stored in plain text on the router, which is bad all around. The OpenVPN site even specifically warns against doing this (I believe in the OpenVPN HowTo). The correct way to do this without having a plugin would be to encrypt the key of the client certs for the users
    • Only server keys should be created with -nodes, of which is covered in the aforementioned Comprehensive wiki.

    • I'm also confused as to why you have openssl.cnf created certs and Easy-RSA certs ?
      • Easy-RSA has never created proper OpenVPN certs due to the laziness of the maintainers

    • md5 & sha1 hashes are not secure

    • CCD [Client Configuration Directory] would be utilized to add an additional layer of security, of which is discussed in the aforementioned Comprehensive wiki

  • You have no TLS-Auth
    • You have the key direction for the tls-auth.key specified (albeit only in the client config and not the server's as well), but no tls-auth.key

  • You have no SSL ciphers specified, let alone EC TLS ciphers

  • Your configs lack tuning, of which will affect your throughput
    • Your tun_mtu should not be 1500... it should be closer to 48000

  • You're utilizing Gateway Redirect, of which is not required with OpenWrt, but is on most other distros.
    • Gateway Redirect on OpenWrt would only be utilized when you want to secure a network behind the router from another network behind the router (this encryption ends at the WAN interface).

Hello JW0914,

I appreciate your complements and thank you for spending the time to review and providing the valuable feedback. I spent the time to do this write-up because, as I mentioned in my original post, there were a lot of individuals who were experiencing similar issues and the wikis were a bit confusing for some beginners (such as myself).

In addition, I did not plagiarizer any work. OpenWRT is an opensource project and I am not making any profit from this nor am I claiming this as my material. I have given my proper credit to the original authors and referenced the location of my sources. Lastly, the link to OpenVPN Setup Guide for Beginners specifically said "This article isn't following the Wiki contribution guide's guidelines, please help improve it." This was the other reason why I decided to expand on it. As of now, there is an updated warning on that page that now reflects the security loopholes you spoke of.

Thank you for finding all the security issues.

You've created a security issue by attempting to implement auth-user-pass, of which should only be implemented on a system that has the appropriate OpenVPN plugin [*.so ], else the passwords will be stored in plain text on the router, which is bad all around.

Yes, you are correct about this but I was not able to find a comprehensive write up on the methods you spoke about. Would you be so kind to provide the URL and the corresponding section in which you are referencing?

Thank you for your feedback on CCD and TLS-Auth that is discussed on the OpenVPN Server (Comprehensive) write-up. I will go back to the drawing board to incorporate these items.

Another reason I wanted to do this write up was to have the community review it and provide their feedback and to inform me (and others) of the security vulnerabilities. I cannot thank you enough for this.

Sincerely,

A humbly committed student

It helps to provide that very reason right at the beginning of the posting.
I read your posting this afternoon. My thoughts were:

  1. ??? (What is the intention of this posting? What is his request?)
  2. after scrolling to the bottom: TL;DR.
  3. seems to be a howto for OpenVPN... but... we already have that at openwrt.org... so why another one?

Thanks for your feedback. @bobafetthotmail wanted to improve this page for long time IIRC, but we volunteers know that free time is always scarce, and lifting a chunk as heavy as this page is requires a lot of time. I don't envy the one doing this job.

1 Like

Hello @tmomas,
I will keep in mind your suggestions of the proper paragraph order to make it easier for the readers. I apologize for any confusion this may have caused.

What issues specifically were you having with either of the two wikis I linked to in my prior post? Provided one follows either of those two wikis, as written, and does not deviate, there should be no issues.

  • I'm more than happy to add any information one believes isn't covered in the Comprehensive wiki linked to in my prior post and below.
    • @stangri and I had a lengthy conversation regarding the OpenVPN (Server Setup) & OpenVPN Server (Comprehensive) wikis, and we decided it was best to have the two separate wikis as:
      • The OpenVPN (Server Setup) wiki is intended to be a no-frills, get up and running as quick as possible, without having to have the user understand all of what's being done or have prior experience with OpenVPN

      • Whereas the OpenVPN Server (Comprehensive) wiki is meant to be a far more in-depth, comprehensive walk through, providing a wealth of information specific to each step in the process.
        • New wiki guidelines were implemented a few months back and I'm still in the process of breaking this wiki up into separate wikis, as it's impractical to have the amount of information in that wiki within it without tab boxes.
          • I've already broken up the OpenSSL steps into it's own wiki, OpenSSL Certificates, and am currently working on a new format so I can get rid of the tab boxes.

As to auth-user-pass, you generally see custom OpenVPN plugin modules that were written for those specific OSes (Sophos UTM, a firewall OS, is a great example of this). There is zero benefit to utilizing auth-user-pass on OpenWrt, as encrypting the client cert's key accomplishes the same thing, with greater security, and combined with CCD, prevents a user from connecting to the VPN, even if they have a valid cert to do so, unless their cert has been listed within the CCD.

There's more than just formatting issues with that wiki, hence the warning wrap at the top of that wiki. Best rule of thumb I have, or at least the one I follow, is I disregard any wiki that's on the old wiki site (wiki.openwrt.org, hence the first wrap at the top of the wiki about it being read only, directing to the new wiki site: https://openwrt.org/docs)

2 Likes

Thank you for that information and explanation @JW0914. Yes, the banner at the top mentioned that the resource I used was for record purposes and to refer to the new wiki. As mentioned, I did not see the reference when originally using the document. I appreciate your organizational skills to avoid clutter and data dumping. The referenced URLs you provided looks very well written and looks to have covered a wide range of items. I will follow those instructions and let you know if I have any questions.

Thanks for your time and energy supporting the cause.

Sincerely,

A humbly committed student

A post was split to a new topic: 17.01 OpenVPN setup