Description:This describes how to enable authentication on OpenVPN, with custom OTP's, but without PAM modules nor online API calls,
using a static file "username".txt (chmod r) and for the anti-replay attack counter "username".cnt (chmod rw).
Requirements:OpenVPN
Auth::Yubikey_Decrypter perl module
In openvpn's server.conf I point to a perl script (named ovpn-yk-val.pl).
Your config file could have a zillion differences according to your needs, but the 3 lines about the perl is what matters here:
Code:
local 1.2.3.4
port 1194
proto udp
dev tun
#
ca /usr/local/etc/openvpn/keys/ca.crt
cert /usr/local/etc/openvpn/keys/server.crt
key /usr/local/etc/openvpn/keys/server.key # This file should be kept secret
dh /usr/local/etc/openvpn/keys/dh1024.pem
#
server 10.8.0.0 255.255.255.0
#
ifconfig-pool-persist ipp.txt
#
topology subnet
push "dhcp-option DNS 99.99.99.99"
push "redirect-gateway def1 bypass-dhcp"
#
script-security 3
username-as-common-name
auth-user-pass-verify "/usr/local/etc/openvpn/ovpn-yk-val.pl" via-env
#
keepalive 10 120
comp-lzo
#
persist-key
persist-tun
status /var/log/openvpn-status.log
log-append /var/log/openvpn.log
verb 3
#
# client-to-client
# max-clients 25
and ovpn-yk-val.pl itself looks like this:
Code:
#!/usr/bin/perl -T
use strict;
use Auth::Yubikey_Decrypter;
# $ENV{"common_name"};
# $ENV{"username"};
# $ENV{"password"};
my $usr = $ENV{"username"};
$usr =~ m/^([a-zA-Z0-9]+)$/;
exit !(length($1) > 0);
my $credsfile = "/usr/local/etc/openvpn/$1.txt";
my $countfile = "/usr/local/etc/openvpn/$1.cnt";
exit !(-e $credsfile);
exit !(-e $countfile);
# get values
open (FILE1, "<", $credsfile) or die "Could not open yubikey credential file.\n";
my @line = <FILE1>;
chomp $line[0];
my @ykdata = split ":" , $line[0];
close FILE1 or die $!;
my $otp = $ENV{"password"};
$otp =~ m/^([a-zA-Z0-9]+)$/;
exit !(length($1) > 0);
# decrypt:
my ($publicID,$secretid_hex,$counter_dec,$timestamp_dec,$session_use_dec,$random_dec,$crc_dec,$crc_ok) =
Auth::Yubikey_Decrypter::yubikey_decrypt($1,$ykdata[1]);
# prepare to check replay attacks
my $ctr32 = (($counter_dec & 0x7fff) << 8) + $session_use_dec;
open (FILE2, "+>", $countfile) or die "Could not open yubikey counter file.\n";
my $counter = do { local $/; <FILE2> };
$counter =~ m/^([0-9]+)$/;
# validate:
if ( $ykdata[0] eq $secretid_hex && $crc_ok == 1 && $ctr32 > $1 ) {
truncate(FILE2, 0);
print FILE2 $ctr32;
close FILE2 or die $!;
exit 0;
}
close FILE2 or die $!;
exit 1;
identity:
In this example there is a "/usr/local/etc/openvpn/$1.txt" and a "/usr/local/etc/openvpn/$1.cnt".
You'll need to add the Private Identity in for example /usr/local/etc/openvpn/john.txt, such that the perl sript can validate against it.
counter:And you need to have a 0 (zero) in the counter file, named /usr/local/etc/openvpn/john.cnt (or whatever path you changed above sample code to) - this is to detect and prevent replay attacks.
When (re)starting OpenVPN now should accept OTP's as credentials.