[ale] HomeVPN
Phil Turmel
philip at turmel.org
Fri Nov 9 12:50:00 EST 2012
On 11/09/2012 10:54 AM, Robert L. Harris wrote:
> I will look into those android apps yet, haven't found one I like.
>
> I've been using SSH since the early 90's, no worries there. I want to
> setup and play with a VPN connection for remote devices. I have OpenVPN
> running out of a linux VM dedicated so i can lock it down and if need be
> wipe it without loss of sleep.
>
> As my original thread went, "Has anyone else done this? Anyone up for
> sharing configs/discussing?"
I've been running OpenVPN on my office server to support home and road
warrior usage for about eight or nine years. Using my own certificate
authority for the past five years or so to minimize router configuration
requirements. Works well with both windows and linux client machines.
I've attached my config files for your edification (lightly sanitized).
The last attachment is my personal script for managing my certificate
authority
HTH,
Phil
-------------- next part --------------
#
# Road warrior VPN based on certificates instead
# of pre-shared private keys.
#
log-append /var/log/openvpn/warriors
status /var/log/openvpn/warrior-status 10
verb 1
local router.example.com
lport 1194
#mlock
# Configure basic server settings, including the
# subnet, protocol, and activity tracking.
dev tun
proto tcp
topology subnet
keepalive 44 180
float
server 192.168.18.0 255.255.255.0
route-gateway 192.168.18.1
push "route-gateway dhcp"
tun-mtu 1500
push "tun-mtu 1500"
# Security setup
ca /etc/ssl/certs/example-ca.pem
dh /etc/openvpn/dh1024.pem
cert /etc/ssl/certs/server-vpn.pem
key /etc/ssl/private/server-vpn.key
persist-key
persist-tun
push "persist-tun"
client-config-dir /etc/openvpn/warriors
ccd-exclusive
user openvpn
group openvpn
# Remember client addresses through service restarts
ifconfig-pool-persist /etc/openvpn/warrior-pool.txt
# Add routes to the client that point to subnets
# reachable through this server.
push "route 192.168.16.0 255.255.240.0"
# Preset routes to subnets that are behind
# specific clients (matching the "iroute" in
# the per-client config file. Also push them
# down to other connected clients.
#route 192.168.2.0 255.255.255.0
#push "route 192.168.2.0 255.255.255.0"
# Allow clients to "see" each other
client-to-client
-------------- next part --------------
# Road Warrior VPN configuration. You must have a X509 certificate
# signed by the Certificate Authority to authenticate your connection.
# The certificate's CN must also have a config file in the server's
# client-config-dir folder. Zero-length is acceptable.
log-append /var/log/openvpn/warriors
# Common settings for all road warriors
remote router.example.com 1194
proto tcp
dev tun
client
verb 1
auth-retry nointeract
ca /etc/ssl/certs/example-ca.pem
# Client-specific identification
cert /etc/ssl/certs/client1-vpn.pem
key /etc/ssl/private/client1-vpn.key
-------------- next part --------------
#! /bin/bash
#
# Alternate Mini Certificate Authority
# Copyright (C) 2010 Philip J. Turmel <philip at turmel.org>
#
# kate: tab-width 4; indent-width 4; tab-indents on; dynamic-word-wrap off;
SDIR=/etc/ssl
CAname=example-ca
SERIAL="$SDIR/CAserial.txt"
REVOKE="$SDIR/CArevoke.txt"
# Display usage assistance, clean up if needed, and exit.
function usage() {
cat <<EOF
Usage:
ca -h
ca certname
ca [-p] -c certname subj-item [subj-item ...]
ca [-p] -r certname [subj-item ...]
ca -x certname
Form #1 displays this help.
Form #2 displays details of an existing certificate name 'certname'.
Form #3 creates a new, signed certificate with the name 'certname'
constructed from the given subject items. Each subject item
must be in the form 'name=value'. Subject items may also be
concatenated with '/', as they will be in the certificate.
Form #4 renews and signs a certificate with the name 'certname',
optionally replacing or adding subject items. Replaced subject
items will remain in their original order. If a subject item
occurs multiple times (like nested OUs) in the original, and
fewer replacements are given, the last new value replaces the
last old value.
Form #5 revokes the certificate named 'certname' by creating a
revocation certificate for it, and putting it on the revocation
list.
The [-p] option requests pass-phrase protection for the new private
key. It will be prompted for.
If 'certname' matches the configured signing certificate name, a new
or renewed signing certificate will be created, and self-signed.
EOF
if [[ -n "$PFILE" ]] ; then
rm "$PFILE"
fi
exit $1
}
# Shared code to combine existing subject strings with new subject
# items, remove unwanted subject items, and verify the presence of
# required subject items.
#
function mksubject() {
local -a original replaced mods rmods checks
local op key keyo keym
# Parse the existing subject into individual items, in reverse
# order.
echo 'Subject:' $subject
while [[ "$subject" =~ ^(.*)/([^/]+)$ ]] ; do
original+=("${BASH_REMATCH[2]}")
subject="${BASH_REMATCH[1]}"
# echo 'Subject:' $subject
done
# Examine all the modifications and checks, executing the deletions
# immediately, and storing the mods and checks for later use.
for x in "$@" ; do
if [[ "$x" =~ ^([+-])([^/=]+)$ ]] ; then
op="${BASH_REMATCH[1]}"
key="${BASH_REMATCH[2]}"
if [[ "$op" == "+" ]] ; then
checks+=("$key")
else
for y in "${!original[@]}" ; do
subjitem="${original[$y]}"
if [[ "$subjitem" =~ ^([^=]+)=(.+)$ ]] ; then
if [[ "$key" == "${BASH_REMATCH[1]}" ]] ; then
unset original[$y]
break
fi
fi
done
fi
else
while [[ "$x" =~ ^([^/]+)(/(.+))?$ ]] ; do
mods+=("${BASH_REMATCH[1]}")
x="${BASH_REMATCH[3]}"
done
if [[ -n "$x" ]] ; then
echo "Unrecognized subject item: $x !"
exit 1
fi
fi
done
# Reverse the mods
for x in "${!mods[@]}" ; do
i=$(( 1000 - $x ))
rmods[$i]="${mods[$x]}"
done
echo
rmods=("${rmods[@]}")
unset mods
echo "Originals: ${original[*]}"
echo "Reversed Mods: ${rmods[*]}"
echo "Post-checks: ${checks[*]}"
# Replace originals with mods, moving them to 'replaced' as we go.
for x in "${!rmods[@]}" ; do
if [[ "${rmods[$x]}" =~ ^([^=]+)=(.+)$ ]] ; then
keym="${BASH_REMATCH[1]}"
for y in "${!original[@]}" ; do
if [[ "${original[$y]}" =~ ^([^=]+)=(.+)$ ]] ; then
keyo="${BASH_REMATCH[1]}"
if [[ "$keym" == "$keyo" ]] ; then
replaced[$y]="${rmods[$x]}"
unset original[$y]
unset rmods[$x]
break
fi
fi
done
if [[ -n "${rmods[$x]}" ]] ; then
for y in "${!replaced[@]}" ; do
z[$(( 1000 - $y ))]=$y
done
for y in "${z[@]}" ; do
if [[ "${replaced[$y]}" =~ ^([^=]+)=(.+)$ ]] ; then
keyo="${BASH_REMATCH[1]}"
if [[ "$keym" == "$keyo" ]] ; then
t="${replaced[$y]}"
replaced[$y]="${rmods[$x]}"
rmods[$x]="$t"
fi
fi
done
unset z
fi
fi
done
echo "Originals: ${original[*]}"
echo "Replacements: ${replaced[*]}"
echo "Reversed Mods: ${rmods[*]}"
echo "Post-checks: ${checks[*]}"
# Recombine the originals and replacements into one array.
for y in "${!replaced[@]}" ; do
echo "Reinserting $y: ${replaced[$y]}, now: ${original[*]}"
original[$y]="${replaced[$y]}"
done
# Reverse the remaining mods again (back to forward order)
for x in "${!rmods[@]}" ; do
i=$(( 1000 - $x ))
mods[$i]="${rmods[$x]}"
done
mods=("${mods[@]}")
unset rmods
# Assemble original and replaced subject items into a single
# subject string. Delete satisfied checks while at it.
subject=""
for x in "${original[@]}" ; do
subjitem="$x"
if [[ "$x" =~ ^([^=]+)=(.+)$ ]] ; then
keyo="${BASH_REMATCH[1]}"
for y in "${!mods[@]}" ; do
if [[ "${mods[$y]}" =~ ^([^=]+)=(.+)$ ]] ; then
keym="${BASH_REMATCH[1]}"
if [[ "$keyo" == "$keym" ]] ; then
subjitem="$subjitem/${mods[$y]}"
unset mods[$y]
fi
fi
done
for y in "${!checks[@]}" ; do
if [[ "$keyo" == "${checks[$y]}" ]] ; then
unset checks[$y]
fi
done
fi
subject="/${subjitem}${subject}"
done
# Assemble remaining subject items to the end of the subject
# string, again deleting satisfied checks.
for x in "${mods[@]}" ; do
if [[ "$x" =~ ^([^=]+)=(.+)$ ]] ; then
keym="${BASH_REMATCH[1]}"
for y in "${!checks[@]}" ; do
if [[ "$keym" == "${checks[$y]}" ]] ; then
unset checks[$y]
fi
done
fi
subject="$subject/$x"
done
checks=("${checks[@]}")
if [[ -n "${checks[*]}" ]] ; then
echo -e "Subject string did not pass the required verification!"
echo -e "The following subject items are missing: ${checks[*]}"
exit 1
fi
}
# Shared code to obtain an encryption passphrase for the new
# private key.
#
function getphrase() {
read -p "Enter the desired private key passphrase: " -s pass1
echo
read -p "Re-enter the desired passphrase: " -s pass2
echo
if [[ "$pass1" != "$pass2" ]] ; then
echo "Pass phrases don't match!"
exit 1
fi
if [[ -z "$pass1" ]] ; then
echo "No passphrase supplied! If you really don't want one,"
echo "omit the '-p' option from the command."
exit 1
fi
chmod 0600 "$PFILE"
echo -n "$pass1" >"$PFILE"
}
# Shared code to create a private key, with ".tmp" tacked onto the
# filename.
#
function mkprivate() {
local PPP
[[ -n "$PFILE" ]] && PPP="-des -passout file:$PFILE"
echo "Creating new private key ..."
if openssl genrsa $PPP -out "$PRIV.tmp" 2048 ; [[ $? -ge 1 ]] ; then
echo "Unable to create the private key!"
exit 1
fi
chmod 600 "$PRIV.tmp"
}
# Shared code to create and sign a certificate, with ".tmp" tacked
# on, presuming the key has already been created by the mkprivate
# function. The subject items must already be concatenated into a
# single argument to this function.
#
function mkcertificate() {
local PPP
newserial=$(( 1 + $(< "$SERIAL" ) ))
[[ -n "$PFILE" ]] && PPP="-passin file:$PFILE"
if [[ "$CERT" == "$CACERT" ]] ; then
echo "Creating and self signing $CERT for subject: $1"
openssl req -new -batch \
-subj "$1" \
-set_serial $newserial \
-x509 -days 3650 \
-out "$CERT.tmp" \
-key "$PRIV.tmp" $PPP
else
echo -e "Creating request $CERT.req for subject: $1"
if openssl req -new -batch \
-subj "$1" \
-out "$CERT.req" \
-key "$PRIV.tmp" $PPP ; [[ $? -ge 1 ]]
then
echo "Unable to create certificate request!"
exit 1
fi
echo "CA signing $CERT ..."
openssl x509 -req \
-in "$CERT.req" \
-out "$CERT.tmp" -outform PEM \
-set_serial $newserial \
-days 730 \
-CA "$CACERT" \
-CAkey "$CAPRIV"
fi
if [[ $? -ge 1 ]] ; then
echo "Unable to create certificate!"
exit 1
fi
echo -n $newserial >$SERIAL
mv -f "$CERT.tmp" "$CERT"
mv -f "$PRIV.tmp" "$PRIV"
rm -f "$CERT.req"
echo -e "Installed $CERT and $PRIV\n"
}
# Shared code to display a finished certificate in a relatively
# human-friendly format.
#
function showcert() {
echo -e "# Certificate $CERT :"
openssl x509 -noout -subject -issuer -dates -fingerprint -in "$CERT" \
| while read line ; do echo "# $line" ; done
}
# Look for the various operating mode options, and set shell
# variables accordingly.
while getopts ":hpcrx" optchar ; do
case $optchar in
h) usage ;;
p) PFILE="`mktemp`" ; chmod 0600 $PFILE ;;
c) CAmode="create" ;;
r) CAmode="renew" ;;
x) CAmode="revoke" ;;
*) echo "Unrecognized option '$optchar':" ; usage 1 ;;
esac
done
shift $(($OPTIND - 1))
# The first remaining option must be the certificate name.
# If no certificate named, bail out with usage instructions.
#
[[ -n "$1" ]] || usage 1
CERT="$SDIR/certs/$1.pem"
PRIV="$SDIR/private/$1.key"
CACERT="$SDIR/certs/$CAname.pem"
CAPRIV="$SDIR/private/$CAname.key"
shift
# Create the serial number and revocation counter files if they
# don't yet exist.
#
[[ -s "$SERIAL" ]] || echo -n 1 >$SERIAL
[[ -s "$REVOKE" ]] || echo -n 1 >$REVOKE
# Create subdirectories if they don't yet exist
#
[[ -d "$SDIR/certs" ]] || mkdir -p "$SDIR/certs"
[[ -d "$SDIR/crl" ]] || mkdir -p "$SDIR/crl"
[[ -d "$SDIR/private" ]] || mkdir -p "$SDIR/private"
# Select the appropriate operations for the requested mode.
#
case "$CAmode" in
create)
echo "Preparing to create $CERT ..."
if [[ "$CERT" != "$CACERT" ]] ; then
subject="`openssl x509 -subject -noout -in \"$CACERT\"`"
if [[ "$subject" =~ ([^/]+)(/.+) ]] ; then
subject="${BASH_REMATCH[2]}"
else
echo "Unable to extract the baseline subject from the Certificate Authority!"
exit 1
fi
else
subject=""
fi
mksubject -CN -emailAddress "$@" +C +ST +L +O +CN
[[ -n "$PFILE" ]] && getphrase
mkprivate
mkcertificate "$subject"
;;
renew)
subject="`openssl x509 -subject -noout -in \"$CERT\"`"
if [[ "$subject" =~ ([^/]+)(/.+) ]] ; then
subject="${BASH_REMATCH[2]}"
else
echo "Unable to extract the original subject from $CERT !"
exit 1
fi
mksubject "$@" +C +ST +L +O +CN
[[ -n "$PFILE" ]] && getphrase
mkprivate
mkcertificate "$subject"
;;
revoke)
echo -e "Revoke is not yet implemented! Sorry!"
exit 1
;;
esac
# All of the operations except revoke return here to display the
# finished certificate.
#
showcert
More information about the Ale
mailing list