summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xlib/Vyatta/VPN/Util.pm48
-rwxr-xr-xscripts/vpn-config.pl25
2 files changed, 67 insertions, 6 deletions
diff --git a/lib/Vyatta/VPN/Util.pm b/lib/Vyatta/VPN/Util.pm
index a40cc90..65877b0 100755
--- a/lib/Vyatta/VPN/Util.pm
+++ b/lib/Vyatta/VPN/Util.pm
@@ -27,10 +27,14 @@ use strict;
use warnings;
our @EXPORT = qw(rsa_get_local_key_file LOCAL_KEY_FILE_DEFAULT rsa_get_local_pubkey
- is_vpn_running vpn_debug enableICMP is_tcp_udp get_protocols conv_protocol);
+ rsa_convert_pubkey_pem is_vpn_running vpn_debug enableICMP is_tcp_udp
+ get_protocols conv_protocol);
use base qw(Exporter);
use Vyatta::Config;
+use Crypt::OpenSSL::RSA;
+use MIME::Base64;
+use File::Copy;
use POSIX qw(strftime);
use constant LOCAL_KEY_FILE_DEFAULT
@@ -110,15 +114,57 @@ sub rsa_get_local_pubkey {
my @raw_data=<$dat>;
close($dat);
+ # PEM encoded private key
+ my $rsa = Crypt::OpenSSL::RSA->new_private_key(join("", @raw_data));
+ if (defined $rsa) {
+ my ($n, $e) = $rsa->get_key_parameters();
+ my $eb = $e->to_bin();
+ return "0s" . encode_base64(pack("C", length($eb)) . $eb . $n->to_bin(), '');
+ }
+
+ # legacy private key format
foreach my $line (@raw_data) {
my $file_pubkey;
if (($file_pubkey) = ($line =~ m/\s+\#pubkey=(\S+)/)) {
+ # Found a legacy private key; convert to PEM for strongSwan 5.2.x
+ my $key = join("", @raw_data);
+ $key =~ /^\s+Modulus:\s+0x([0-9a-fA-F]+)$/m;
+ my $n = Crypt::OpenSSL::Bignum->new_from_hex($1);
+ $key =~ /^\s+PublicExponent:\s+0x([0-9a-fA-F]+)$/m;
+ my $e = Crypt::OpenSSL::Bignum->new_from_hex($1);
+ $key =~ /^\s+PrivateExponent:\s+0x([0-9a-fA-F]+)$/m;
+ my $d = Crypt::OpenSSL::Bignum->new_from_hex($1);
+ $key =~ /^\s+Prime1:\s+0x([0-9a-fA-F]+)$/m;
+ my $p = Crypt::OpenSSL::Bignum->new_from_hex($1);
+ $key =~ /^\s+Prime2:\s+0x([0-9a-fA-F]+)$/m;
+ my $q = Crypt::OpenSSL::Bignum->new_from_hex($1);
+
+ my $rsa = Crypt::OpenSSL::RSA->new_key_from_parameters($n, $e, $d, $p, $q);
+ if (defined $rsa) {
+ # write out PEM formatted key
+ move("$file", "$file.bak");
+ open(my $priv, '>', "$file")
+ or return 0;
+ chmod 0600, $file;
+ print {$priv} $rsa->get_private_key_string();
+ close($priv);
+ }
return $file_pubkey;
}
}
return 0;
}
+sub rsa_convert_pubkey_pem {
+ my $key = shift;
+ my $decoded = decode_base64($key);
+ my $len = unpack("C", substr($decoded, 0, 1));
+ my $e = Crypt::OpenSSL::Bignum->new_from_bin(substr($decoded, 1, $len));
+ my $n = Crypt::OpenSSL::Bignum->new_from_bin(substr($decoded, 1 + $len));
+ my $rsa = Crypt::OpenSSL::RSA->new_key_from_parameters($n, $e);
+ return $rsa->get_public_key_x509_string();
+}
+
sub vpn_debug {
my $timestamp = strftime("%Y%m%d-%H:%M.%S", localtime);
diff --git a/scripts/vpn-config.pl b/scripts/vpn-config.pl
index dd5da34..c7e227c 100755
--- a/scripts/vpn-config.pl
+++ b/scripts/vpn-config.pl
@@ -59,6 +59,7 @@ my $dhcp_if = 0;
my $genout;
my $genout_secrets;
my %key_file_list;
+my %public_keys;
# Set $using_klips to 1 if kernel IPsec support is provided by KLIPS.
# Set it to 0 us using NETKEY.
@@ -1010,7 +1011,10 @@ if ($vcVPN->exists('ipsec')) {
vpn_die(["vpn","ipsec","site-to-site","peer",$peer,"authentication"],"$vpn_cfg_err Unable to determine local public key from local key".
" file \"$local_key_file\" for peer \"$peer\".\n");
} else {
- $genout .= "\tleftrsasigkey=\"$local_key\"\n";
+ if (!defined($public_keys{localhost})) {
+ $public_keys{localhost} = $local_key;
+ $genout .= "\tleftsigkey=localhost.pub\n";
+ }
}
my $rsa_key_name = $vcVPN->returnValue("ipsec site-to-site peer $peer authentication rsa-key-name");
@@ -1023,7 +1027,10 @@ if ($vcVPN->exists('ipsec')) {
vpn_die(["vpn","ipsec","site-to-site","peer",$peer,"authentication"],"$vpn_cfg_err No remote key configured for rsa key name ".
"\"$rsa_key_name\" that is specified for peer \"$peer\".\n");
} else {
- $genout .= "\trightrsasigkey=\"$remote_key\"\n";
+ if (!defined($public_keys{$rsa_key_name})) {
+ $public_keys{$rsa_key_name} = $remote_key;
+ $genout .= "\trightsigkey=$rsa_key_name.pub\n";
+ }
}
}
# Prevent duplicate includes for rsa keys.
@@ -1156,13 +1163,13 @@ if ( $vcVPN->isDeleted('.')
if (!enableICMP('1')) {
vpn_die(["vpn","ipsec"],"VPN commit error. Unable to re-enable ICMP redirects.\n");
}
- write_config($genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if);
+ write_config($genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if, %public_keys);
} else {
if (!enableICMP('0')) {
vpn_die(["vpn","ipsec"],"VPN commit error. Unable to disable ICMP redirects.\n");
}
- write_config($genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if);
+ write_config($genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if, %public_keys);
# Assumming that if there was a local IP missmatch and clustering is enabled,
# then the clustering scripts will take care of starting the VPN daemon.
@@ -1251,7 +1258,7 @@ sub vpn_die {
}
sub write_config {
- my ($genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if) = @_;
+ my ($genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if, %public_keys) = @_;
open my $output_config, '>', $config_file
or die "Can't open $config_file: $!";
@@ -1272,6 +1279,14 @@ sub write_config {
print ${output_secrets} $genout_secrets;
close $output_secrets;
dhcp_hook($dhcp_if);
+
+ for my $name (keys %public_keys) {
+ my $output_path = "/etc/ipsec.d/certs/$name.pub";
+ open my $output_file, '>', $output_path
+ or die "Can't open $output_path: $!";
+ print ${output_file} rsa_convert_pubkey_pem($public_keys{$name});
+ close $output_file;
+ }
}
sub vpn_exec {