#!/usr/bin/perl # verify-cn -- a sample OpenVPN tls-verify script # # Return 0 if cn matches the common name component of # X509_NAME_oneline, 1 otherwise. # # For example in OpenVPN, you could use the directive: # # tls-verify "./verify-cn Test-Client" # # This would cause the connection to be dropped unless # the client common name is "Test-Client" die "usage: verify-cn certificate_depth X509_NAME_oneline" if (@ARGV != 2); # Parse out arguments: # cn -- The common name which the client is required to have, # 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. use DBI; ($depth, $x509) = @ARGV; $result="0"; 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. if ($x509 =~ /\/serialNumber=([^\/]+)/) { # Accept the connection if the X509 common name # string matches the passed cn argument. my $dbh = DBI->connect('DBI:mysql:sslvpn', 'sslvpn', 'sslvpn') or die "Couldn't connect to database: " . DBI->errstr; my $sth = $dbh->prepare("SELECT `id`, `name`, `firstname` FROM `users` WHERE id=$1") or die "Couldn't prepare statement: " . $dbh->errstr; my @data; $sth->execute() or die "Couldn't execute statement: " . $sth->errstr; # Read the matching records and print them out while (@data = $sth->fetchrow_array()) { $id = $data[0]; $name = $data[1]; $firstname = $data[2]; #print "Database result: \t$id: $firstname $name\n"; } # Authentication failed -- Either we could not parse # the X509 subject string, or the common name in the # subject string didn't match the passed cn argument. if ($sth->rows == 0) { print "TLS-VERIFY: EE - Unknown user: $x509\n"; $result=1; } # Authentication is OK else { print "TLS-VERIFY: OK - $id - '$firstname $name' logged in\n"; $result=0; } $sth->finish; $dbh->disconnect; } } # If depth is nonzero, tell OpenVPN to continue processing # the certificate chain. That's why $result = 0 by default exit $result;