Synology-Forum.nl
Tweaks / Addons A.K.A. The Underground => Overige mods => Topic gestart door: Pippin op 02 oktober 2015, 14:06:42
-
Doel: Clients mogen geen certificaten met elkaar kunnen uitwisselen.
1. Elke client heeft zijn eigen certificaat met een unieke commonname die anders is als zijn/haar gebruikersnaam. Dat is al voor elkaar.
2. De server controleert de gebruikersnaam/wachtwoord. Dat is standaard en gebeurt middels een radius plugin.
3. Na controle van 2. moet de unieke commonname van het certificaat, van de betreffende client, gecontroleerd worden.
De combinatie gebruikersnaam/commonname zijn dus uniek.
Wanneer nu een client certificaat ingetrokken wordt, kan deze niet met het certificaat van een andere gebruiker inloggen.
Ik heb meerdere scripts (shell, perl, php, python) gevonden maar ik denk dat het aangepast moet worden om op de DS te functioneren en daar heb ik dus hulp bij nodig.
Hoe werkt het:
In de config van de server kun je o.a. via de optie tls-verify een script aanroepen, in dit geval een shell script, de optie ziet er zo uit:
tls-verify "/volume1/@appstore/VPNCenter/scripts/ovpnCNcheck.sh /volume1/@appstore/VPNCenter/scripts/userlist.txt"
Zodra een client verbind wordt eerst zijn gebruikersnaam/wachtwoord (standaard radius plugin) en vervolgens de commonname gecontroleerd.
De commonname staat in userlist.txt
Als de server een 0 terugkrijgt van het script heeft de client toegang, komt er een 1 terug dan niet.
Hieronder staat het script, het is uitvoerbaar gemaakt en de commonname staat in de userlist.
Voor zover ik kan zien zit ook Apparmor niet in de weg maar wil van de week als test dit script nog wel toevoegen aan het Apparmor profile.
Dit staat in het messages log:
WARNING: Failed running command (--tls-verify script): external program exited with error status: 1
Ik heb alles inmiddels meerdere keren doorgelopen maar kom er niet achter waar de fout zit.
#!/bin/sh
# ovpnCNcheck -- an OpenVPN tls-verify script
# """""""""""""""""""""""""""""""""""""""""""
#
# This script checks if the peer is in the allowed
# user list by checking the CN (common name) of the
# X509 certificate against a provided text file.
#
# For example in OpenVPN, you could use the directive
# (as one line):
#
# tls-verify "/usr/local/sbin/ovpnCNcheck.py
# /etc/openvpn/userlist.txt"
#
# This would cause the connection to be dropped unless
# the client common name is within the userlist.txt.
#
# Special care has been taken to ensure that this script
# also works on openwrt systems where only busybox is
# available
#
# Written by Robert Penz <robert@penz.name> under the GPL 2
# Parts are copied from the verify-cn sample OpenVPN
# tls-verify script.
[ $# -eq 3 ] || { echo usage: ovpnCNcheck.sh userfile certificate_depth X509_NAME_oneline ; exit 255 ; }
# $2 -> certificate_depth
if [ $2 -eq 0 ] ; then
# $3 -> X509_NAME_oneline
# $1 -> cn we are looking for
grep -q "^`expr match "$3" ".*/CN=\([^/][^/]*\)"`$" "$1" && exit 0
exit 1
fi
exit 0
-
Voor zover ik kan zien zit ook Apparmor niet in de weg maar wil van de week als test dit script nog wel toevoegen aan het Apparmor profile.
Dit klopt feitelijk niet.
Ik had middels het Apparmor profiel het VPN proces toegang gegeven tot de ovpnCNcheck.sh en userlist.txt
Ik weet dus niet of de "........error status: 1" melding komt doordat het script een 1 terugstuurt naar de server of dat het script aangepast dient te worden om op een DS te kunnen draaien.
Ideeën zijn welkom...
-
Zojuist de python versie van het script geprobeert.
#!/usr/bin/python
'''
ovpnCNcheck -- an OpenVPN tls-verify script
"""""""""""""""""""""""""""""""""""""""""""
This script checks if the peer is in the allowed
user list by checking the CN (common name) of the
X509 certificate against a provided text file.
For example in OpenVPN, you could use the directive
(as one line):
tls-verify "/usr/local/sbin/ovpnCNcheck.py /etc/openvpn/userlist.txt"
This would cause the connection to be dropped unless
the client common name is within the userlist.txt.
Every line should hold one regular expression which
can also be just one common name (don't forget to escape
stuff like .?^()[]\ with a \).
Empty or lines which start with a # are ignored.
Written by Robert Penz <robert@penz.name> under the GPL 2
Parts are copied from the verify-cn sample OpenVPN
tls-verify script.
'''
# Version 0.1
# Initial Release
import sys
import re
def matchCommonName(userListFile, cn):
""" reads the user list file and tries to match every regex """
for rawLine in open(userListFile,"r").readlines():
line = rawLine.strip().rstrip("\n")
if not line or line[0] == "#":
continue
if re.compile(line).match(cn):
return True
return False
def main():
# we only work with 3 parameters
if len(sys.argv) != 4:
print __doc__
sys.exit(-1)
# Parse out arguments:
# userListFile -- Path of the file with the allowed users
# taken from the argument to the tls-verify directive
# in the OpenVPN config file.
# depth -- The current certificate chain depth. In a typical
# bi-level chain, the root certificate will be at level
# 1 and the client certificate will be at level 0.
# This script will be called separately for each level.
# x509 -- the X509 subject string as extracted by OpenVPN from
# the client's provided certificate.
(userListFile, depth, x509) = sys.argv[1:]
if depth == "0":
# If depth is zero, we know that this is the final
# certificate in the chain (i.e. the client certificate),
# and the one we are interested in examining.
# If so, parse out the common name substring in
# the X509 subject string.
found = re.compile(r"/CN=(?P<cn>[^/]+)").search(x509)
if found:
# Accept the connection if the X509 common name
# string matches a regex
if matchCommonName(userListFile, found.group("cn")):
sys.exit(0)
# Authentication failed -- Either we could not parse
# the X509 subject string, or the common name in the
# subject string didn't match the user list regexes
sys.exit(1)
# If depth is nonzero, tell OpenVPN to continue processing
# the certificate chain.
sys.exit(0)
if __name__ == '__main__':
main()
Omdat het resultaat hetzelfde openvpn.log oplevert vermoed ik dat ik het op de DS moet zoeken.
Eerste verdachte is Apparmor, ook al krijg ik daar geen melding van in het kern.log.
Ideeën zijn nog steeds welkom
-
Met Apparmor uitgeschakeld hetzelfde resultaat.
Met hulp bij troubleshooting op een mailinglijst van OpenVPN heb ik nu, echo "[$0] [$1] [$2] [$3] [$4]" aan het shell script toegevoegd.
Dat levert een extra regel in het log op:
[/volume1/@appstore/VPNCenter/scripts/ovpnCNcheck.sh] [/volume1/@appstore/VPNCenter/scripts/userlist.txt] [0] [C=NL, ST=GLD, O=MMD, OU=OVPN-NAS, CN=xxxxxx, emailAddress=xxxxxx@xxxxxx.com] []
Het lijkt er dus op dat het shell script het client certificaat wel ontvangt en leest, tenzij ik dat verkeerd interpreteer.
En nog steeds zijn ideeën welkom :-)
-
Het blijkt dat het shell script verouderd is.
Door:
grep -q "^`expr match "$3" ".*/CN=\([^/][^/]*\)"`$" "$1" && exit 0
te vervangen door:
grep -q "^`expr match "$3" ".* CN=\([^,]*\)"`$" "$1" && exit 0
werkt het nu.
Ik heb een denkfout gemaakt, de bedoeling was dat een client alleen met zijn certificaat kan inloggen.
Echter wat er nu gebeurt is:
Client logt in
Gebruikersnaam/Wachtwoord wordt gecheckt door radius.
CommonName van het certificaat wordt gecheckt door het script.
Als ik nu inlog met gebruikerA maar met het certificaat van gebruikerB krijg ik toch toegang.
Dit komt omdat de Gebruikersnaam niet gekoppelt is aan de CommonName van het certificaat.
Een certificaat heeft een uniek serienummer en een unieke x509v3 Subject Key Identifier
Dat zou dan ook gebruikt kunnen worden in een script.....denk ik.
Ik heb dus nog wat zoekwerk te doen.
Tenzij er iemand een ideetje heeft :lol:
-
Uiteindelijk dan toch gelukt, echter niet met een tls-verify script.
Dat bleek minder geschikt voor het beoogde resultaat.
Met de tip, die ik elders kreeg, het met een auth-user-pass-verify script te doen was ik goed geholpen.
Het is dus uiteindelijk dit geworden:
#!/bin/sh
echo "[${username}] [${X509_0_CN}]"
user1="Jan"
cn1="commonnamevanJan`s-certificaat"
user2="Piet"
cn2="commonnamevanPiet`s-certificaat"
user3="Sjaak"
cn3="commonnamevanSjaak`s-certificaat"
test "$user1" = "${username}" && test "$cn1" = "${X509_0_CN}" && exit 0
test "$user2" = "${username}" && test "$cn2" = "${X509_0_CN}" && exit 0
test "$user3" = "${username}" && test "$cn3" = "${X509_0_CN}" && exit 0
exit 1
Het script opslaan als un-cn-check.sh met rechten 0755 en plaatsen in:
/volume1/@appstore/VPNCenter/scripts
Aan de config van de server toevoegen:
auth-user-pass-verify /volume1/@appstore/VPNCenter/scripts/un-cn-check.sh via-env
script-security 2
En, indien niet reeds aanwezig, in de config van de client:
auth-user-pass
En als laatste, voeg een regel toe aan het Apparmor profiel van OpenVPN:
/volume1/@appstore/VPNCenter/apparmor/pkg_VPNCenter
#include <tunables/global>
/volume*/@appstore/VPNCenter/sbin/openvpn {
#include <abstractions/base>
#include <abstractions/base-cgi>
capability chown,
capability net_bind_service,
/dev/net/tun rw,
/usr/syno/etc/packages/VPNCenter/openvpn/** rwk,
/volume*/@appstore/VPNCenter/bin/synovpnnet ix,
/volume*/@appstore/VPNCenter/etc/openvpn/keys/** r,
/volume*/@appstore/VPNCenter/etc/openvpn/radiusplugin.cnf r,
/volume*/@appstore/VPNCenter/etc/synovpncon.sql r,
/volume*/@appstore/VPNCenter/etc/synovpnlog.sql r,
/volume*/@appstore/VPNCenter/lib/** mr,
/volume*/@appstore/VPNCenter/sbin/openvpn ix,
/volume*/@appstore/VPNCenter/scripts/openvpn.sh rix,
/volume1/@appstore/VPNCenter/scripts/un-cn-check.sh rix, #deze toevoegen
/volume*/@appstore/VPNCenter/var/log/ r,
/volume*/@appstore/VPNCenter/var/log/*.db* rwk,
Het is helaas een eenzaam topic..... :D
-
Inderdaad is het een eenzame Topic geworden :lol:
Wel gevolgd, maar heb er verder geen verstand van.....dus......maar, het staat op het Forum dus, misschien hebben de (toekomstige/huidige) leden er wel wat aan. ;)
Bedankt in ieder geval.
-
Echt veel verstand heb ik er ook niet van.
Heb alleen iets voor ogen en probeer daar dan wat bij te zoeken zodat het werkt.
Is gewoon een leuke hobby zullen we maar zeggen.