Synology OpenVPN Setup

Configuring a secure OpenVPN implementation on Synology NAS devices

Prerequisites

Secure your Synology NAS before enabling internet access. Follow this document before proceeding.

You need to setup dynamic DNS in order to access your WAN IP from the public internet. Most people have DHCP from the ISP. As a result the WAN IP address may change from time to time. There are numerous free and paid dynamic DNS services available. Feel free to pick anything you desire. You can setup dynamic DNS on most home routers. You can also setup dynamic DNS on the Synology NAS as well.

You don't need your own domain to use OpenVPN. Nor do you need a Let's Encrypt certificate. It is best to create your own CA (Certificate Authority) and sign your own certificates. The setup of the root CA is described in detail below.

Setup port forwarding on your home router. The default port for OpenVPN is 1194/UDP. But you can choose any port and change the protocol as well. Every router has a different interface. Use https://portforward.com/ for instructions if needed. Do not buy there little tool. Port forwarding is quite simple to setup. It is recommended to setup a DHCP reservation or use a static IP address for your Synology NAS device. Setting up either option varies from device to device and is beyond the scope of this document.

Official Documentation

The user should always read the official documentation first. This document is based on the official documents plus a few other websites. The official documents will help explain in detail all of the various settings.

For the root CA (certificate authority) I mainly used the directions from the Feisty Duck SSL cookbook. I also borrowed from a few different websites. The openssl.cnf file has tons of options. And there are probably better ways to configure it. I previously created my own CA on my DD-WRT router. This setup is a bit better. And I suspect if I do this in the future I will learn a bit more then. The OpenVPN setup has also improved over my DD-WRT setup. I used a few websites to help setup OpenVPN.

  1. Deprecated OpenVPN Commands - Some of my options will be deprecated in the near future. But for now Synology is running version 2.3.x.
  2. Hardening OpenVPN - I took some of these suggestions.
  3. Another hardening guide
  4. A third hardening guide

High Level Overview

This is a very long document. But the steps are not hard. I found a new WordPress plugin that will allow for tabs. That will make long documents like this a lot more usable.

I created a script to help setup the root-ca and make it easier. And to make it more consistent. The script follows the high level procedures below. More information about the script can be found at the bottom of this document.

Transfer SYNO-OVPN.tar.gz to your NAS. This file has my script and a few configuration files. And it includes a nice little README file.

  1. Install the Synology OpenVPN package
  2. Configure the Synology OpenVPN package
  3. Test the Synology OpenVPN package before making any manual changes.

Now use the script or follow the manual directions to build your own root CA and to secure OpenVPN. Extract the files in /tmp or in /root. It will make a sub-directory name 'SYNO-OVPN'.

Now edit the files and update the variables for your environment. Use the included README for instructions on what to edit. Then run './syno-ovpn.ash build) to setup the basic directory structure and copy over a few configuration files.

  1. Setup the directory structure for the Root CA (./syno-ovpn.ash BUILD)
    1. Setup /etc/ssl/root-ca and sub-directories
    2. Copy the key files
  2. Switch to /etc/ssl/root-ca. Double check the configuration files and finish editing them if required. The script renamed some of the files when it copied them to the new directory.
    1. /etc/ssl/root-ca/openssl.conf
    2. /usr/syno/etc/packages/VPNCenter/openvpn/openvpn.conf
    3. /etc/ssl/root-ca/ovpn/openvpn.client.ovpn
    4. /etc/ssl/root-ca/syno-ovpn.ash (Script mentioned above)
  3. Setup the Root CA (./syno-ovpn.ash root-ca)
  4. Setup the Diffie Hellman file (./syno-ovpn.ash DH)
  5. Add Users (./syno-ovpn.ash -f john -l doe add)
    1. This will create the CSR and private key for the user
    2. Sign the CSR and create the public key for the user
    3. Setup an OVPN file for the user
  6. The script will also make it easier to revoke client certificates
    (./syno-ovpn.ash -f john -l doe revoke)
  7. Overwrite the Synology openvpn.conf server configuration file with our more secure configuration.
  8. Manually add the new SSL/TLS certificates to the Synology GUI for the OpenVPN package
    1. server.key (server private key)
    2. server.crt (server public key)
    3. ca.crt (Root CA public key)

Install the OpenVPN Package

Synology has a VPN Server package. It has 3 VPN protocols.

  • PPTP = Point to Point Tunneling Protocol (Do not use. There are known security vulnerabilities.)
  • L2TP/IPSec - Layer 2 Tunneling Protocol with IPSec (Internet Protocol Security) - L2TP doesn't encrypt. Encryption is done by IPSec. There may be security issues with IPSec.
  • OpenVPN - Recommended - Very configurable and it is open source.

Go to the package center and install 'VPN Server'. Once it is installed go to the main menu and select VPN Server. There are very few native configuration options within this package. Click on the 'OpenVPN' tab and fill in the information as desired.

  • Check 'Enable OpenVPN Server'
  • Dynamic IP address = Pick any /24 private subnet you desire. In this example I am using 10.1.1.0/24.
  • Maximum connection number = choose a number from the drop down box (5, 10, or 15)
  • Maximum number of connections with the same account - I changed this to '1' from the default value of '3'. By default the Synology OpenVPN uses ID and password. I plan to change this to certificate authentication for better security.
  • Port = 1194 (Default) - It is a good idea to change this to another port to reduce port scanning. Additional layers of security are always a good thing.
  • Protocol = UDP (Default) You can change this to TCP if you like. Some people use 443/TCP to help them connect through various firewalls. If possible use UDP.
  • Encryption = AES-256-CBC - Choose this or another encryption algorithm. NOTE: This cipher is being deprecated. Perhaps the next release of OpenVPN on Synology will have current ciphers.
  • Authentication = SHA512 - Do not use SHA1 anymore. SHA256 is probably more than enough. But I went for the highest HMAC.
  • Check "Enable compression on the VPN link"
  • [OPTIONAL] - Check "Allow clients to access server's LAN - Enable this if you want to SSH or RDP to other boxes on your home LAN.
  • [OPTIONAL] - Do not check - Enable IPv6 server mode. Most people are not using IPv6 at this time.
  • Click 'Apply'
OpenVPN Configuration Panel
OpenVPN Configuration Panel

Update the Synology Firewall

Based on the document 'Securing Synology NAS' mentioned above update your firewall to allow 1194/UDP. Or choose another port if desired.

Before changing anything else test out the basic configuration. Export your configuration from the OpenVPN GUI. Edit it with your dynamic DNS name. And install it on your phone or something else. Make sure everything works before proceeding.

Create Your Own CA

The default Synology OpenVPN setup uses ID and password for authentication. This is not recommended for several reasons. I am following the hardening guide from OpenVPN. At the time of this writing Synology is running OpenVPN v2.3.11 and OpenSSL v1.0.2n-fips. Two factor authentication is not an option with the Synology OpenVPN server at this time. It may be possible to compile the code yourself and update PAM.

NOTE: Once you manually update the configuration files you cannot hit 'apply' in the VPN Server configuration panel GUI. It will overwrite your settings. Make a backup of all your changes. It is possible that package updates may overwrite things as well.

Follow the steps below to configure your CA (Certificate Authority). The v1.0.2 MAN pages are here. And links to the main commands used are shown below with a brief explanation of each option.

GENRSA Man Page - genrsa - Generates an RSA private key.

CA Man Page - ca - This is a minimal CA application. It can be used to sign certificate requests (CSR) in a variety of forms and generate CRLs. It also maintains a text database of issued certificates and their status.

REQ Man Page - req - PKCS#10 certificate request and certificate generating utility. The req command primarily creates and processes certificate requests in PKCS#10 format. It can additionally create self signed certificates for use as a root CA.

X509 Man Page - x509 - A certificate display and signing utility. The x509 command is a multi purpose certificate utility. It can be used to display certificate information, convert certificates to various forms, sign certificate requests like a 'mini CA' or edit certificate trust settings.

Please note that in all of the commands below we must specify the updated openssl.conf file using the '-config' flag. We are not using the system default file.

1. Setup a New SSL Directory

Synology OpenSSL uses '/etc/ssl' as the default directory. (openssl version -d) I don't want to mess up any of the other items using SSL. So I will create a new openssl.conf file and directory structure for my CA. SSH to the Synology NAS and run the following commands as root or use sudo.

  • # Temporarily change the umask to ensure the newly created files and directories are secure
    • umask 0077
  • # Make a new directory for root-ca - /etc/ssl/root-ca
    • mkdir -m 0700 /etc/ssl/root-ca
  • # Change to that directory to lessen the amount of typeing
    • cd /etc/ssl/root-ca
  • # Make the sub-directories (certs - For PEM formatted certificates 'hash_of_name.pem' // db - For text based control files // private - For the private keys '*.key' // pub - For the public certificates '*.crt' // csr - For the certificate signing request '*.csr')
    • mkdir -m 0700 certs db private pub csr
  • # Optionally make a directory to hold the OpenVPN OVPN client configuration files for each user. Note, my script requires this directory.
    • mkdir -m 700 ovpn
  • # Each private key should be secured by a unique strong password. To help secure these files the directory is only available to 'root'.
    • chmod 0700 private
  • # Seed the '.rand' file. This file is used to help create entropy.
    • dd if=/dev/urandom of=/etc/ssl/root-ca/private/.rand bs=256 count=1
  • # For extra security we limit access to this file.
    • chmod 0600 /etc/ssl/root-ca/private/.rand
  • # Create the text based database file for openssl.
    • touch db/index
  • # Create a random unique string to start the count of each public key. Each public key gets the next number in the sequence.
    • openssl rand -hex 16 > db/serial
  • #The number with which to start a sequence of numbers to identify revoked certificates. Each one will get a unique number.
    • echo 1001 > db/crlnumber
  • # For security make sure everything is owned by root. On other systems it is best not to run this as root.
    • chown -R root:root /etc/ssl/root-ca

2. Create a New Openssl.conf (aka openssl.cnf)

Now we need to create a new openssl.conf file. The file should be owned by 'root:root' with permissions of 0600. Synology OpenSSL uses '/etc/ssl/openssl.cnf' as the configuration file. You can copy that file over, or use the file from the *.tar.gz file I provide. The script from the *.tar.gz file will copy over the initial file.

  • vi /etc/ssl/openvpn/openssl.conf

I am using the Feisty Duck site and PKI tutorials to help me configure the openssl.cnf file. I am not creating OCSP responders. Use the sample file below to create openssl.conf. Edit the lines in blue as desired.

# The [default] section contains global constants that
# can be referred to

# from the entire configuration file. It may also hold
# settings pertaining to # more than one openssl command.

# EDIT AS APPROPRIATE
# base_url = http://FQDN of your NAS
# Optional - update aia_url and crl_url
[ default ]

default_ca          = ca_default            # The default CA section
base_url            = http://your_nas.lab.example.com
aia_url             = $base_url/pub/ca.crt
crl_url             = $base_url/ca.crl
name_opt            = utf8,esc_ctrl,multiline,lname,align
prompt              = yes

# EDIT THIS AS APPROPRIATE
# Update countryName, stateOrProvince, localityName & organizationName
# Optional - update commonName
# CA Distinguished Name (DN) - called from req section

[ ca_dn ]
countryName          = "US"
stateOrProvinceName  = "IL"
localityName         = "Chicago"
organizationName     = "Lava VPN"

commonName           = "Root CA"

# The CA section defines the locations of CA assets, as
# well as the policies

# applying to the CA. Used by the 'openssl ca' command
[ ca_default ]
home                = /etc/ssl/root-ca     # Base directory
database            = $home/db/index       # dB index file
serial              = $home/db/serial      # Serial number file
crlnumber           = $home/db/crlnumber   # CRL number file
certificate         = $home/ca.crt         # CA public cert
private_key         = $home/private/ca.key # CA private key
RANDFILE            = $home/private/.rnd # Private random number file
new_certs_dir       = $home/certs       # Public certs directory
unique_subject      = no                # Require unique subject
copy_extensions     = none              # Copy extensions from the CSR
default_days        = 3650              # Certify for 10 years
default_crl_days    = 365               # How long until next CRL
crl_extensions      = crl_ext           # CRL extensions
default_md          = sha512            # Default signature algorithm
copy_extensions     = none              # Copy extensions from CSR

policy              = match_pol         # Default naming policy
x509_extensions     = client_ext        # Default signing extensions

# The next part of the configuration file is used by the
# openssl req command.
# It defines the CA's key pair, its DN, and the desired
# extensions for the CA 
certificate.
[ req ]
default_bits        = 2048        # RSA key size
encrypt_key         = yes         # Protect private key
default_md          = sha512      # MD to use
utf8                = yes         # Input is UTF-8
string_mask         = utf8only    # Emit UTF-8 strings
prompt              = no          # Don't prompt for DN
distinguished_name  = ca_dn       # DN section
x509req_extensions  = ca_reqext   # Extensions for CA self-signed

# Extensions for CA self-signed Cert ca.crt
[ ca_reqext ]

keyUsage                  = critical,keyCertSign,cRLSign
basicConstraints          = critical,CA:true,pathlen:0
extendedKeyUsage          = clientAuth,serverAuth
subjectKeyIdentifier      = hash
authorityKeyIdentifier    = keyid:always

# Naming policies control which parts of a DN end
# up in the certificate and

# under what circumstances certification should be denied.
[ match_pol ]
countryName           = match     # Must match cn_dn
stateOrProvinceName   = match     # Must match cn_dn
localityName          = match     # Must match cn_dn
organizationName      = match     # Must match cn_dn
commonName            = supplied  # Must be present

# Certificate extensions define what types of
# certificates the CA is able to
 create.
[ root_ca_ext ]
keyUsage                 = critical,keyCertSign,cRLSign
basicConstraints         = critical,CA:true,pathlen:0
subjectKeyIdentifier     = hash
authorityKeyIdentifier   = keyid:always

# CRL extensions exist solely to point to the CA
# certificate that has issued
 the CRL.
[ crl_ext ]
authorityKeyIdentifier    = keyid:always

# Extensions used to create server
[server_ext]
keyUsage                 = critical,digitalSignature,keyEncipherment
basicConstraints         = critical,CA:false
extendedKeyUsage         = clientAuth,serverAuth
authorityKeyIdentifier   = keyid:always
subjectKeyIdentifier     = hash

# Extensions used to create clients
[client_ext]
keyUsage                 = critical,digitalSignature
basicConstraints         = critical,CA:false
extendedKeyUsage         = clientAuth
authorityKeyIdentifier   = keyid:always
subjectKeyIdentifier     = hash
#
#EOF

3. Create the Diffie Hellman Parameters

I think you can use elliptic curve (EC) parameters instead of Diffie Hellman (DH) parameters. But I need to do some more research. I am using the 'dsaparam' flag to drastically reduce the amount of time it takes to create the file. I am using 2048 bits. Do not use 1024. And 4096 is overkill at this time.

  • cd /etc/ssl/openvpn
  • openssl dhparam -dsaparam -rand /dev/urandom -out dh2048.pem 2048

NOTE: This command will still take around 15 to 30 minutes to complete. Newer more powerful Synology NAS devices may require a bit less time.

4. Create the TLS Auth

Creating a TLS auth key helps to harden your VPN. It is a static pre-shared key (PSK) that must be generated in advance and shared among all peers.

  • cd /etc/ssl/openvpn
  • openvpn --genkey --secret private/ta.key

NOTE: This is not an OpenSSL command. It is an OpenVPN command.

On the OpenVPN server configuration file we must add the following line.

  • tls-auth /path/to/ta.key 0

On the clients we will be using inline files (concatenate all crt and key files into the OVPN file). The client configuration file needs the following line.

  • key-direction 1

5. Create the Root CA

The command below will generate a private key file (ca.key) and a public key file (ca.crt) for our new CA. When prompted, supply a secure password for the private key. Keep track of this password.

  • cd /etc/ssl/openvpn
  • openssl req \
    -config ./openssl.conf \
    -days 3650 \
    -x509 \
    -new \

    -keyout private/ca.key \
    -out pub/ca.crt

Check the private and public keys.

  • Private:  openssl rsa -in private/ca.key -check
  • Private:  openssl rsa -in private/ca.key -text -noout
  • Public:  openssl x509 -in pub/ca.crt -text -noout

Verify that the public key (ca.crt) has the correct distinguished name defined by openssl.conf. And verify that the x509v3 extensions list it as a CA.

We will also convert the CA crt to PEM format. This allows us to run 'openssl verify' commands against newly signed certificates.

  • openssl x509 \
    -in pub/ca.crt \
    -outform PEM \
    -out pub/ca.pem

6. Create the CRL (Revocation List)

Our default CRL days is 365. We need to create a new CRL every 365 days. Normally this is 30 days. But this is for a small personal OpenVPN instance. We want this as easy to manage as possible. Now create the CRL file before we create any other keys.

  • cd /etc/ssl/openvpn
  • openssl ca \
    -config ./openssl.conf \

    -gencrl \
    -extensions crl_ext \
    -out ca.crl

NOTE: You must recreate the file every time you revoke a client.

Read the contents with the following command.

  • openssl crl -in ca.crl -text -noout

Revoke a Certficate

The serial number of each CRT is stored in the database. (db/index) Grep for the name in the file and you can see the serial number. The serial number is shown in bold blue in the example below.

grep CN=john.doe db/index

V 280410224051Z 1BA302853C5C152075698774AC393A04 unknown /C=US/ST=IL/L=Chicago/O=Lava VPN/CN=john.doe

You must supply a reason for the revocation. Choose one of the following reasons.

  • unspecified
  • keyCompromise
  • CACompromise
  • affiliationChanged
  • superseded
  • cessationOfOperation
  • certificateHold
  • removeFromCRL

Use the command below to revoke a certificate. Update as appropriate. Make sure you create a new ca.crl file after each certification revocation.

  • openssl ca \
    -config ./openssl.conf \

    -revoke certs/1BA302853C5C152075698774AC393A04.pem \
    -crl_reason keyCompromise

7. Create the Server Key, CSR, & Crt

Now create the server private key (server.key) and CSR (server.csr). Adjust your '-subj' flags as required to match whatever you set in the 'openssl.cnf' file for the CA. When prompted enter a password for the private key (server.key). We need to remove the password for this key as Synology does not support authentication on the server key.

  • cd /etc/ssl/openvpn
  • openssl req \
    -config ./openssl.conf \
    -days 3650 \
    -new \

    -subj '/C=US/ST=IL/L=Chicago/O=Lava VPN/CN=server' \
    -extensions server_ext \
    -keyout private/server.key \
    -out csr/server.csr

Synology will not accept encrypted private keys. We must remove the password from the server private key. When prompted provide the password for the server private key.

  • openssl rsa -in private/server.key -out private/server.key

Now sign the CSR and generate the public key (server.crt). Remember you need to sign the CSR with the password for the CA private key (ca.key). Next we will verify that the public key has the correct information. Check to see the DN is correct and that the x509 extensions are correct. It should not be a CA and should point to the CA issuers public key (ca.crt).

  • cd /etc/ssl/openvpn
  • openssl ca \
    -config ./openssl.conf \
    -extensions server_ext \
    -days 3650 \

    -subj '/C=US/ST=IL/L=Chicago/O=Lava VPN/CN=server' \
    -in csr/server.csr \
    -out pub/server.crt
  • openssl x509 -in pub/server.crt -text -noout

8. Create the Client Key, CSR, & Crt

We will use the first and last name of the person for each client certificate. The first and last names will be separated by a '.' (period /aka dot). You can add a '-' (dash) or another '.' (period /aka dot) to either name to help with repeated names. For example you can use 'john.doe-jr' or 'john.doe.jr' as the name. Update the 'subj' flag with the correct DN. Make sure you use client extensions.

Just like the server setup we need to create a private key and a CSR. Then we need to sign the CSR and create the public key. Make sure you use the client extensions.

First create the CSR and private key. Make sure you create a new secure password for the private key and keep track of it.

  • cd /etc/ssl/openvpn
  • openssl req \
    -config ./openssl.cnf \
    -days 3650 \
    -new \

    -subj '/C=US/ST=IL/L=Chicago/O=Lava VPN/CN=john.doe' \
    -extensions client_ext \
    -keyout private/john.doe.key \
    -out csr/john.doe.csr

Now sign the CSR and create the public key. Remember you need to sign the CSR with the password for the CA private key (ca.key).

  • cd /etc/ssl/openvpn
  • openssl ca \
    -config ./openssl.cnf \
    -extensions client_ext \
    -days 3650 \

    -subj '/C=US/ST=IL/L=Chicago/O=Lava VPN/CN=john.doe' \
    -in csr/john.doe.csr \
    -out pub/john.doe.crt
  • openssl x509 -in pub/john.doe.crt -text -noout

Repeat these steps to add more clients.

Setup OpenVPN Server Configuration

OpenVPN provides a fully annotated sample openvpn server configuration file. They also provide a fully annotated sample client openvpn.ovpn file. To determine the default server configuration file run 'ps -aux | grep openvpn' on your NAS. The default location is shown below.

  • /usr/syno/etc/packages/VPNCenter/openvpn/openvpn.conf

The script mentioned in this document will copy the 'openvpn.conf' file copied below to "/etc/ssl/root-ca/ovpn/openvpn.conf.SERVER.SAMPLE". Edit this script as required. Then copy it over the default config shown above. Feel free to make additional changes. At a minimum you need to edit the push routes and the server VLAN. And you can also change the port if desired.

#
# OpenVPN Server Config
# Edit as appropriate
#

# Push routes to clients for local LAN subnet
# intranet - most home routers use 192.168.1.0/24
push "route 192.168.1.0 255.255.255.0"
# VPN network - choose whatever /24 you desire
push "route 10.2.192.0 255.255.255.0"

# Set Subnet mode
topology subnet

# VPN Server Subnet - OpenVPN uses x.x.x.1
server 10.2.192.0 255.255.255.0

# Do not allow split-tunneling
# Force ALL traffic through VPN
push "redirect-gateway def1"

# Listen on port (UDP or TCP) default 1194
port 1194

# Set Protocol - tcp or udp
proto udp

# Synology only supports TUN (L3)
# Set device tun/tap
dev tun0

# Keepalive n m = ping n ping-restart m
# ping every 10 seconds // restart after no ping in 60 sec
keepalive 10 60

# Renegotiate data channel key after N seconds (default=3600)
# 0 = disable
reneg-sec 0

# SSL/TLS certificates created by OpenSSL - root-ca
# ca = Root CA Self Signed Cert
# key = server running on Root CA private key
# cert = server running on Root CA public key
# dh = Diffie Hellman Parameters
# Syno default dir = /var/packages/VPNCenter/target/etc/openvpn/keys
ca /etc/ssl/root-ca/pub/ca.crt
key /etc/ssl/root-ca/private/server.key
cert /etc/ssl/root-ca/pub/server.crt
dh /etc/ssl/root-ca/dh2048.pem

# "HMAC FW" - helps block DoS attacks and UDP port flooding
# openvpn --genkey --secret ta.key
tls-auth /etc/ssl/root-ca/private/ta.key 0

# CRL Revocation List File Location
crl-verify /etc/ssl/root-ca/ca.crl

# Select a cryptographic cipher. (symmetric)
# Used by 'data channel'
# NOTE: OpenVPN 2.4 has newer ciphers GCM
# openvpn --show-ciphers
cipher AES-256-CBC

# Select Auth - auth alg
# openvpn --show-digests

# Authenticate packets with HMAC
auth SHA512

# For compression compatible with older clients use comp-lzo
# If you enable it here, you must also
# enable it in the client config file.
comp-lzo adaptive

# The maximum number of concurrently connected
# clients we want to allow.
max-clients 5

# The persist options will try to avoid
# accessing certain resources on restart
# that may no longer be accessible because
# of the privilege downgrade.
persist-key
persist-tun

# Limit TLS v1.2
tls-version-min 1.2

# Limit TLS ciphers to those listed below
# Used by 'control channel'
# openvpn --show-tls
# EC and ECDSA tls ciphers only availble in 2.4 or higher
# tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384:TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA:TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA
# Using list below as this is v2.3.x
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256

# Limit scripting level
# 0 - no calling of external programs
# 1 (default) only call built-in executables - ifconfig, ip, netsh
# 2 allow calling of user defined scripts
# 3 allow passwords to be passed to scripts via environmental variables (unsafe)
script-security 2

# Ensure clients have EKU - extended key usage - set to client
# Clients must be set to use server
# remote-cert-eku "TLS Web Server Authentication"
remote-cert-eku "TLS Web Client Authentication"

# Output a short status file showing
# current connections, truncated
# and rewritten every N (30 sec)
status /tmp/ovpn_status_2_result 30

# Status version N - 1, 2 or 3
status-version 2

# Set the appropriate level of log
# file verbosity.
#
# 0 is silent, except for fatal errors
# 4 is reasonable for general usage
# 5 and 6 can help to debug connection problems
# 9 is extremely verbose
verb 3
# EOF

Setup OpenVPN Client Configuration

Edit the included sample client configuration to match your server configuration. Then for each new client change the name to easily identify each OVPN file. And concatenate the certificates in the proper order. First put CA certificate (ca.crt). Second add the new client public certificate. Third add the new client private key. And fourth add the TLS authentication file (ta.key).

The client configuration file will be identical with 3 exceptions.

  1. For Windows clients comment out the 'user nobody' and 'group nobody' lines.
  2. Each client will have their own unique client public key. (john.doe.crt)
  3. Each client will have their own unique client private key. (john.doe.key)

Edit the sample file below as appropriate. Make sure you add the certificates.

#
# OpenVPN Client Config
# Needs to match server config
# Edit as appropriate
#

# Specify that we are a client and that we
# will be pulling certain config file directives
# from the server.
client

# Use the same setting as you are using on
# the server.
# On most systems, the VPN will not function
# unless you partially or fully disable
# the firewall for the TUN/TAP interface.
dev tun0

# Are we connecting to a TCP or
# UDP server? Use the same setting as
# on the server.
proto udp

# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
# Should be dyn dns hostname
remote dyn.dns.name.for.nas 1194

# Keep trying indefinitely to resolve the
# host name of the OpenVPN server. Very useful
# on machines which are not permanently connected
# to the internet such as laptops.
resolv-retry infinite

# Most clients don't need to bind to
# a specific local port number.
nobind

# Downgrade privileges after initialization (non-Windows only)
# WINDOWS - COMMENT OUT USER AND GROUP NOBODY
; user nobody
; group nobody

# Try to preserve some state across restarts.
persist-key
persist-tun

# Verify server certificate by checking that the
# certicate has the correct key usage set.
# This is an important precaution to protect against
# a potential attack discussed here:
# http://openvpn.net/howto.html#mitm
remote-cert-tls server

# If a tls-auth key is used on the server
# then every client must also have the key.
key-direction 1

# Allow remote peer to change IP (DHCP)
# Accept authenticated packets from any address
# not just address specified by 'remote' option
float

# Select a cryptographic cipher.
# If the cipher option is used on the server
# then you must also specify it here.
# Note that v2.4 client/server will automatically
# negotiate AES-256-GCM in TLS mode.
# See also the ncp-cipher option in the manpage
cipher AES-256-CBC

# Select HMAC Authentication
# server/client must match
auth SHA512

# Verify EKU - Extended Key Usage is set to server on remote box
remote-cert-eku "TLS Web Server Authentication"

# Set TLS to min of 1.2
tls-version-min 1.2

# Enable compression on the VPN link.
# Don't enable this unless it is also
# enabled in the server config file.
comp-lzo adaptive

# Set log file verbosity.
verb 0

# To simplify OVPN client setup concatenate
# all certificates here in proper order
# 1 <ca> </ca> 2 <cert> </cert>
# 3 <key> </key> 4 <tls-auth> </tls-auth>
# ADD CERTS BELOW HERE

Concatenate the Client OVPN

The script will create our client OVPN file. If you do this manually you need to concatenate all of the files into the client OVPN file.

  • Add the user to the root CA using the commands above.
  • Copy the sample OVPN file and create a client OVPN file. (john.doe.ovpn)
  • Add the ca.crt file, client crt file, client key file, and ta.key. Each file must be enclosed with the identifiers shown below.

<ca>
cat ca.crt here
</ca>
<cert>
cat john.doe.crt here
</cert>
<key>
cat john.doe.key here
</key>
<tls-auth>
cat ta.key here
</tls-auth>

Overwrite the Synology openvpn.conf File

Copy are new OpenVPN server configuration file  and overwrite the default Synology openvpn.conf file. Our new file is shown below.

  • /etc/ssl/root-ca/ovpn/openvpn.conf.SERVER

The default file is shown below.

  • /usr/syno/etc/packages/VPNCenter/openvpn/openvpn.conf

Add Our Server Keys to the GUI

By default Synology uses the self-signed synology certificate for everything. We need to add a new certificate to the DSM GUI and then configure OpenVPN to use that new certificate. It has to be a chained certificate and include our new server.key (private key), the server.crt (public key), and the new root CA public certificate (ca.crt).

I tar these three files up before I transfer them.

  • /etc/ssl/root-ca/pub/ca.crt (Root CA public certificate)
  • /etc/ssl/root-ca/pub/server.crt (OpenVPN server public certificate)
  • /etc/ssl/root-ca/private/server.key (OpenVPN server private certificate)

Extract the files somewhere on your computer. Then launch the DSM GUI. (https://your_nas:5001)

  • Next launch the 'Control Panel'.
  • Navigate to 'Security' and then open the 'Certificate Tab'.
  • Click 'Add'
    • Choose 'Add a new certificate' and click 'Next'
    • Choose 'Import certificate'. Optionally add a description. Click 'Next'.
    • Now import the server.key, server.crt, and ca.crt. See the picture below.
      Import Certificate Files Screen
      Import Certificate Files Screen

      Click OK to import the certificate. Then highlight your new certificate and click 'Configure'. Select 'server' (or what you used for a description) in the drop down box next to 'VPN Server'. And then click OK.

      Select 'server' Certificate
      Select 'server' Certificate

       

Restart OpenVPN

Restart OpenVPN so that it loads the new configuration. You may do this from the GUI or from the command line.

In the GUI open 'Package Center' and then scroll to 'VPN Server'. Open that and use the drop down box labeled 'Action' and select 'Stop'. Use the same box to start the VPN server again.

From a command line run the following command.

  • synoservice --restart pkgctl-VPNCenter
  • Or: /var/packages/VPNCenter/scripts/start-stop-status {stop start}

To check out your server configuration you may run the following.

  • cd /usr/syno/etc/packages/VPNCenter/openvpn
  • openvpn --config ./openvpn.conf

Using the Script

Setting everything up manually isn't that difficult. And it is very useful to help learn about SSL and OpenVPN. But adding or revoking users can be a pain if you have to remember the correct syntax. I created a script to help build the root CA. And it will add and revoke users as well. I mentioned the script above. It is included in 'SYNO-OVPN.tar.gz'. The README file shows you how to use the script. And it explains how to edit the included sample files.  Enjoy.

OpenSSL Certificate Authority (CA) 101

Create your own Certificate Authority (CA). These directions are based upon the Feisty Duck documentation. This document shows you how to setup your own root authority and subordinate CA. And it includes OCSP.

Read the Docs

These directions are based upon the Feisty Duck directions.  It also helps to read the OpenSSL documentation.  Arch Linux has a decent WIKI article as well.  I built myself an OpenSSL CA a while back.  But the Feisty Duck directions are much better than the very basics.

.local

I am using 'lab.pahoehoe.local' for my domain.  I originally tried to use 'lab.pahoehoe.net'.  But I have been too lazy to finish setting up my home ESXi host and internal VLANs.  Once I finish this task I can setup internal DNS and properly use 'lab.pahoehoe.net'.

Identify the Proper Directory

Different distributions will compile OpenSSL with different directories.  Use 'openssl version -a |grep DIR' to identify the directory for your box.

$ openssl version -d  (Raspbian / Debian)
OPENSSLDIR: "/usr/lib/ssl"
pi@pi2:~ $ ls -l /usr/lib/ssl
total 4
lrwxrwxrwx 1 root root 14 May 3 23:03 certs -> /etc/ssl/certs
drwxr-xr-x 2 root root 4096 May 27 11:11 misc
lrwxrwxrwx 1 root root 20 May 3 23:03 openssl.cnf -> /etc/ssl/openssl.cnf
lrwxrwxrwx 1 root root 16 May 3 23:03 private -> /etc/ssl/private

# openssl version -d  (CentOS 7 / RHEL 7)
OPENSSLDIR: "/etc/pki/tls"
[root@zl01lab01 ~]# ls -l /etc/pki/tls
total 12
lrwxrwxrwx. 1 root root 49 Jul 5 19:37 cert.pem -> /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
drwxr-xr-x. 2 root root 112 Jul 5 19:37 certs
drwxr-xr-x. 2 root root 69 Jul 5 19:37 misc
-rw-r--r--. 1 root root 10923 Mar 5 2015 openssl.cnf
drwxr-xr-x. 2 root root 6 Jun 29 2015 private

Create the ROOT CA

Pick a directory for the configuration files.  You will create new directories and a new configuration file for the root CA.  My root CA will be on my CentOS 7 box.

  • cd /etc/pki
  • mkdir root-ca
  • cd /etc/pki/root-ca
  • mkdir certs db private pub csr
  • chmod 700 private
  • touch db/index
  • openssl rand -hex 16 > db/serial
  • echo 1001 > db/crlnumber
  • vi /etc/pki/root-ca/root-ca.conf  (See 'root-ca.conf and sub-ca.conf' below)

Now we can create the root CA CSR, private key and public key.  Plus we will create the CRL (Certificate Revocation List) and the OCSP certificates.  You must export the RANDFILE variable or openssl will default to '~/.rnd'.  Not that it matters either way.

export RANDFILE=/etc/pki/root-ca/private/.rnd

Create the root CA CSR (./root-ca.csr) and private key (./private/root-ca.key).  You must enter a passphrase.  But we will delete that passphrase.  You can keep it if desired.

openssl req -new \
-config root-ca.conf \
-out root-ca.csr \
-keyout private/root-ca.key

Remove the passphrase.

openssl rsa -in private/root-ca.key -out private/root-ca.key

Now we can self sign our CSR and create the public key (./root-ca.crt).

openssl ca -selfsign \
-config root-ca.conf \
-in root-ca.csr \
-out root-ca.crt \
-extensions ca_ext

To generate a CRL use the '-gencrl' command as shown below.  The output will be './root-ca.crl'.

openssl ca -gencrl \
-config root-ca.conf \
-out root-ca.crl

OCSP Responder

The feisty duck directions provide a basic OCSP (Online Certificate Status Protocol).  If you have a lightweight web server you can configure that to respond to the OCSP queries.  Or you could move that to another server entirely.  OCSP is better than CRL (Certificate Revocation List).  But it still puts a burden on the CA and adds additional exposure to the CA.  If you sniff the packets when you log into an HTTPS site you will notice that your laptop also queries the OCSP responder.

OCSP stapling is a better solution.  The HTTPS site will periodically query the CA and then provide a timestamp in the TLS handshake to the client.  The client does not query the OCSP server directly.  Obviously you cannot include the OCSP responder URL in the server certificate.  I need to read more about OCSP stapling.  However, I have seen a number of VM appliances that are black boxes.  I am not sure if they support OCSP stapling.

Perform this on the root CA and the sub CA.

  • Create a key and CSR for the OCSP responder.  You may choose to remove the passphrase on the private key.  See the example above.

openssl req -new \
-newkey rsa:2048 \
-subj "/C=US/O=Lava Dreams/CN=OSCP Root Responder" \
-keyout private/root-ocsp.key \
-out csr/root-ocsp.csr

  • Second use the root CA to issue a certificate.  The days are shortened since this certifcate cannot be revoked.

openssl ca \
-config root-ca.conf \
-in csr/root-ocsp.csr \
-out pub/root-ocsp.crt \
-extensions ocsp_ext \
-days 30

  • Start the OCSP Responder - Ideally this would be done in an HTTPD server on a standard port.

openssl ocsp -port 9080 -index db/index \
-rsigner pub/root-ocsp.crt \
-rkey private/root-ocsp.key \
-CA root-ca.crt -text &

Create the SUB CA

The steps are very similar.  I am using my Raspberry PI for my subordinate CA (aka intermediate CA).  Edit the configuration file as appropriate.

  • cd /etc/ssl
  • mkdir sub-ca
  • cd /etc/ssl/sub-ca
  • mkdir certs db private pub csr
  • chmod 700 private
  • touch db/index
  • openssl rand -hex 16 > db/serial
  • echo 1001 > db/crlnumber
  • vi /etc/ssl/sub-ca/sub-ca.conf  (See 'root-ca.conf and sub-ca.conf' below)

Now create the CSR (./sub-ca.csr) and the private key (./private/sub-ca.key).  This is done on the SUB CA.

openssl req -new \
-config sub-ca.conf \
-out sub-ca.csr \
-keyout private/sub-ca.key

Remove the passphrase.

openssl rsa -in private/sub-ca.key -out private/sub-ca.key

Transfer the CSR (sub-ca.csr) to the ROOT CA.  Then using the ROOT CA create a certificate for the SUB CA.

openssl ca \
-config root-ca.conf \
-in sub-ca.csr \
-out certs/sub-ca.crt \
-extensions sub_ca_ext

Transfer the 'sub-ca.crt' to the SUB CA.  Place it in '/etc/ssl/sub-ca/sub-ca.crt'.

Create a Certificate Chain

Some applications will not accept our CRT from our intermediate (SUB-CA).  We need to provide the application with the certificate chain.  The root-ca.crt and the sub-ca.crt files need to be converted to the PEM format and concatenated together.  The order is important on some older versions of java.  So use the following order.

  1. private key (if applicable / not recommended)
  2. client certificate (server.crt - convert to PEM)
  3. intermediate certificate (sub-ca.pem)
  4. root certificate (root-ca.pem)

From the root CA perform the following steps.

  • openssl x509 -in root-ca.crt -outform pem -out root-ca.pem
  • openssl x509 -in sub-ca.crt -outform pem -out sub-ca.pem
  • cat sub-ca.pem root-ca.pem > server-chain.pem  (copy the output to the SUB CA)

OCSP Responder

Perform the following steps to create the SUB CA OCSP responder.

  • Create a key and CSR for the OCSP responder.  You may choose to remove the passphrase on the private key.  See the example above.

openssl req -new \
-newkey rsa:2048 \
-subj "/C=US/O=Lava Dreams/CN=OSCP SUB-CA Responder" \
-keyout private/sub-ocsp.key \
-out csr/sub-ocsp.csr

  • Second use the root CA to issue a certificate.  The days are shortened since this certifcate cannot be revoked.

openssl ca \
-config sub-ca.conf \
-in csr/sub-ocsp.csr \
-out pub/sub-ocsp.crt \
-extensions ocsp_ext \
-days 30

  • Start the OCSP Responder - Ideally this would be done in an HTTPD server on a standard port.

openssl ocsp -port 9081 -index db/index \
-rsigner pub/sub-ocsp.crt \
-rkey private/sub-ocsp.key \
-CA sub-ca.crt -text &

SUB CA Operations

Now we can sign CSR and issue new server or client certificates.  Most of the time we will issue server certificates.  Use unique names so you can identify each file.  Typically this is the short hostname.

Server Certificates

openssl ca \
-config sub-ca.conf \
-in csr/${SERVER}.csr \
-out pub/${SERVER}.crt \
-extensions server_ext

This will create a 'SERIAL_NUM.pem' file in certs.  The serial number is the same number listed in db/serial.

Client Certificates

openssl ca \
-config sub-ca.conf \
-in csr/${CLIENT}.csr \
-out pub/${CLIENT}.crt \
-extensions client_ext

Import 'root-ca.crt' into Windows

The local trust store must be updated to include our new CA.  You can do this in Windows by following the steps below.  Transfer 'root-ca.crt' to your local box.

Chrome & MS Edge & MS Internet Explorer Browsers

  • Start // Run // inetcpl.cpl
  • Click on the 'Content' tab
  • Click on 'Certificates'
  • Click on the 'Trusted Root Certification Authorities' tab
  • Click 'Import...'
  • Click 'Next'
  • Browse to your 'root-ca.crt' file, click 'Open' and then 'Next'
  • Ensure that it is being placed in the 'Trusted Root Certification Authorities' Certificate store and click 'Next'
  • Review and click 'Finish'
  • Click 'Yes' on the Security Warning
  • Click 'OK' and click 'Close' on the Certificates Window
  • Click 'OK' on the Internet Properties window

Firefox Browser

  • Launch Firefox
  • Open a new tab and type in 'about:preferences'
  • Click Advanced
  • Click Certificates
  • Click 'View Certificates'
  • On the 'Authorities' tab click 'Import...'
  • Navigate to 'root-ca.crt' and click 'Open'
  • Click on 'Trust this CA to identify websites' and click 'OK'
  • Click 'OK'

Convert Files and View Files

You may need to convert a CRT file to a PEM file.  Or do some other sort of conversion.  Different applications expect different types of file formats.  You may also need to verify the contents or extract the contents of various files.

CRT to PEM - PEM to CRT

openssl x509 -in XYZ.crt -outform PEM -out XYZ.pem

openssl x509 -in XYZ.pem -outform der -out XYZ.crt

DER to PEM

openssl x509 -in XYZ.crt -inform DER -outform PEM -out XYZ.pem

Read the CSR or CRT or PEM

openssl req -in X.csr -text -noout

openssl x509 -in cert.crt -text -noout

openssl x509 -in X.pem -text -noout

Check a Private Key

openssl rsa -in X.key -check

Generate a New Private Key and CSR

openssl req -new -nodes -days 3650 -newkey rsa:4096 \
-keyout PRIVATE.key -out X.csr \
-subj "/C=US/ST=IL/L=Chicago/O=Lava Dreams/CN=hostname.lab.pahoehoe.local"

root-ca.conf and sub-ca.conf

You need to edit this file to suit your environment.  The blue lines must be edited.  There are other possible changes that you may make.  But you must read the official documentation to understand what you may or may not want to change.  This sample configuration file has both the root and subordinate CA information.

[default]
# ROOT-CA # name              = root-ca
# SUB-CA # name               = sub-ca
domain_suffix                 = lab.pahoehoe.local
aia_url                       = http://$name.$domain_suffix/$name.crt
crl_url                       = http://$name.$domain_suffix/$name.crl
# ROOT-CA # ocsp_url          = http://ocsp.$name.$domain_suffix:9080
# SUB-CA # ocsp_url           = http://ocsp.$name.$domain_suffix:9081
default_ca                    = ca_default
name_opt                      = utf8,esc_ctrl,multiline,lname,align

[ca_dn]
countryName                   = "US"
organizationName              = "Lava Dreams"
# ROOT-CA # commonName        = "Root CA"
# SUB-CA # commonName         = "Sub CA"

[ca_default]
home                          = .
database                      = $home/db/index
serial                        = $home/db/serial
crlnumber                     = $home/db/crlnumber
certificate                   = $home/$name.crt
private_key                   = $home/private/$name.key
RANDFILE                      = $home/private/.rnd
new_certs_dir                 = $home/certs
unique_subject                = no
# ROOT-CA # copy_extensions   = none
# ROOT-CA # default_days      = 3650
# ROOT-CA # default_crl_days  = 365
# SUB-CA # copy_extensions    = copy
# SUB-CA # default_days       = 365
# SUB-CA # default_crl_days   = 30
default_md                    = sha256
policy                        = policy_c_o_match

[policy_c_o_match]
countryName                   = match
stateOrProvinceName           = optional
organizationName              = match
organizationalUnitName        = optional
commonName                    = supplied
emailAddress                  = optional

[req]
default_bits                  = 4096
encrypt_key                   = yes
default_md                    = sha256
utf8                          = yes
string_mask                   = utf8only
prompt                        = no
distinguished_name            = ca_dn
req_extensions                = ca_ext

[ca_ext]
basicConstraints              = critical,CA:true
keyUsage                      = critical,keyCertSign,cRLSign
subjectKeyIdentifier          = hash

[sub_ca_ext]
authorityInfoAccess           = @issuer_info
authorityKeyIdentifier        = keyid:always
basicConstraints              = critical,CA:true,pathlen:0
crlDistributionPoints         = @crl_info
extendedKeyUsage              = clientAuth,serverAuth
keyUsage                      = critical,keyCertSign,cRLSign
nameConstraints               = @name_constraints
subjectKeyIdentifier          = hash

[crl_info]
URI.0                         = $crl_url

[issuer_info]
caIssuers;URI.0               = $aia_url
OCSP;URI.0                    = $ocsp_url

[name_constraints]
permitted;DNS.0=lab.pahoehoe.local
permitted;DNS.1=lab.pahoehoe.org
excluded;IP.0=0.0.0.0/0.0.0.0
excluded;IP.1=0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0

[ocsp_ext]
authorityKeyIdentifier        = keyid:always
basicConstraints              = critical,CA:false
extendedKeyUsage              = OCSPSigning
keyUsage                      = critical,digitalSignature
subjectKeyIdentifier          = hash

#
# SUB-CA ONLY server_ext & client_ext
#

# [server_ext]
# authorityInfoAccess         = @issuer_info
# authorityKeyIdentifier      = keyid:always
# basicConstraints            = critical,CA:false
# crlDistributionPoints       = @crl_info
# extendedKeyUsage            = clientAuth,serverAuth
# keyUsage                  = critical,digitalSignature,keyEncipherment
# subjectKeyIdentifier        = hash

# [client_ext]
# authorityInfoAccess         = @issuer_info
# authorityKeyIdentifier      = keyid:always
# basicConstraints            = critical,CA:false
# crlDistributionPoints       = @crl_info
# extendedKeyUsage            = clientAuth
# keyUsage                    = critical,digitalSignature
# subjectKeyIdentifier        = hash
# EOF