###############################################################################
# #
# IPFire.org - A linux based firewall #
-# Copyright (C) 2007-2020 IPFire Team <info@ipfire.org> #
+# Copyright (C) 2007-2022 IPFire Team <info@ipfire.org> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
close FILE;
}
if (open(FILE, ">${General::swroot}/certs/index.txt.attr")) {
- print FILE "";
+ print FILE "unique_subject = yes";
close FILE;
}
unlink ("${General::swroot}/certs/index.txt.old");
}
if (! -s ">${General::swroot}/certs/index.txt.attr") {
open(FILE, ">${General::swroot}/certs/index.txt.attr");
+ print FILE "unique_subject = yes";
close(FILE);
}
unlink ("${General::swroot}/certs/index.txt.old");
my $opt = shift;
my $retssl = `/usr/bin/openssl $opt 2>&1`; #redirect stderr
my $ret = '';
- foreach my $line (split (/\n/, $retssl)) {
- &General::log("ipsec", "$line") if (0); # 1 for verbose logging
- $ret .= '<br>'.$line if ( $line =~ /error|unknown/ );
- }
- if ($ret) {
- $ret= &Header::cleanhtml($ret);
+
+ if ($?) {
+ foreach my $line (split (/\n/, $retssl)) {
+ &General::log("ipsec", "$line") if (0); # 1 for verbose logging
+ $ret .= '<br>' . &Header::escape($line);
+ }
}
+
return $ret ? "$Lang::tr{'openssl produced an error'}: $ret" : '' ;
}
###
sub getCNfromcert ($) {
#&General::log("ipsec", "Extracting name from $_[0]...");
my $temp = `/usr/bin/openssl x509 -text -in $_[0]`;
- $temp =~ /Subject:.*CN = (.*)[\n]/;
+ $temp =~ /Subject:.*CN\s*=\s*(.*)[\n]/;
$temp = $1;
$temp =~ s+/Email+, E+;
$temp =~ s/ ST = / S = /;
unlink ($filename);
goto UPLOADCA_ERROR;
} else {
- move($filename, "${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem");
- if ($? ne 0) {
+ unless(move($filename, "${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem")) {
$errormessage = "$Lang::tr{'certificate file move failed'}: $!";
unlink ($filename);
goto UPLOADCA_ERROR;
print "Content-Disposition: attachment; filename=cacert.pem\r\n\r\n";
my @cert = &General::system_output("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ca/cacert.pem");
- print "@cert";
+ print join("", @cert);
exit(0);
}
###
print "Content-Disposition: attachment; filename=hostcert.pem\r\n\r\n";
my @cert = &General::system_output("/usr/bin/openssl", "x509", "-in", "${General::swroot}/certs/hostcert.pem");
- print "@cert";
+ print join("", @cert);
exit(0);
}
###
+### Regenerate the host certificate
+###
+} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'regenerate host certificate'}) {
+ $errormessage = ®enerate_host_certificate();
+
+###
### Form for generating/importing the caroot+host certificate
###
} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'generate root/host certificates'} ||
$cgiparams{'ACTION'} eq $Lang::tr{'upload p12 file'}) {
+ &newcleanssldatabase();
+
if (-f "${General::swroot}/ca/cacert.pem") {
$errormessage = $Lang::tr{'valid root certificate already exists'};
goto ROOTCERT_SKIP;
# Extract the CA certificate from the file
&General::log("ipsec", "Extracting caroot from p12...");
if (open(STDIN, "-|")) {
- my $opt = " pkcs12 -cacerts -nokeys";
+ my $opt = " pkcs12 -legacy -cacerts -nokeys";
$opt .= " -in $filename";
$opt .= " -out /tmp/newcacert";
$errormessage = &callssl ($opt);
if (!$errormessage) {
&General::log("ipsec", "Extracting host cert from p12...");
if (open(STDIN, "-|")) {
- my $opt = " pkcs12 -clcerts -nokeys";
+ my $opt = " pkcs12 -legacy -clcerts -nokeys";
$opt .= " -in $filename";
$opt .= " -out /tmp/newhostcert";
$errormessage = &callssl ($opt);
if (!$errormessage) {
&General::log("ipsec", "Extracting private key from p12...");
if (open(STDIN, "-|")) {
- my $opt = " pkcs12 -nocerts -nodes";
+ my $opt = " pkcs12 -legacy -nocerts -nodes";
$opt .= " -in $filename";
$opt .= " -out /tmp/newhostkey";
$errormessage = &callssl ($opt);
if (!$errormessage) {
&General::log("ipsec", "Moving cacert...");
- move("/tmp/newcacert", "${General::swroot}/ca/cacert.pem");
- $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0);
+ unless(move("/tmp/newcacert", "${General::swroot}/ca/cacert.pem")) {
+ $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
+ }
}
if (!$errormessage) {
&General::log("ipsec", "Moving host cert...");
- move("/tmp/newhostcert", "${General::swroot}/certs/hostcert.pem");
- $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0);
+ unless(move("/tmp/newhostcert", "${General::swroot}/certs/hostcert.pem")) {
+ $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
+ }
}
if (!$errormessage) {
&General::log("ipsec", "Moving private key...");
- move("/tmp/newhostkey", "${General::swroot}/certs/hostkey.pem");
- $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0);
+ unless(move("/tmp/newhostkey", "${General::swroot}/certs/hostkey.pem")) {
+ $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
+ }
}
#cleanup temp files
&General::log("ipsec", "Creating host cert...");
if (open(STDIN, "-|")) {
my $opt = " req -sha256 -nodes";
- $opt .= " -newkey rsa:2048";
+ $opt .= " -newkey rsa:4096";
$opt .= " -keyout ${General::swroot}/certs/hostkey.pem";
$opt .= " -out ${General::swroot}/certs/hostreq.pem";
$errormessage = &callssl ($opt);
open(FILE, "${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
my @p12 = <FILE>;
close(FILE);
- print "@p12";
+ print join("", @p12);
exit (0);
# Allow nothing or a string (DN,FDQN,) beginning with @
# with no comma but slashes between RID eg @O=FR/C=Paris/OU=myhome/CN=franck
- if ( ($cgiparams{'LOCAL_ID'} !~ /^(|[\w.-]*@[\w. =*\/-]+|\d+\.\d+\.\d+\.\d+)$/) ||
- ($cgiparams{'REMOTE_ID'} !~ /^(|[\w.-]*@[\w. =*\/-]+|\d+\.\d+\.\d+\.\d+)$/) ||
+ if ( ($cgiparams{'LOCAL_ID'} !~ /^(|[\w.-]*@[@#]?[\w. =*\/-]+|\d+\.\d+\.\d+\.\d+)$/) ||
+ ($cgiparams{'REMOTE_ID'} !~ /^(|[\w.-]*@[@#]?[\w. =*\/-]+|\d+\.\d+\.\d+\.\d+)$/) ||
(($cgiparams{'REMOTE_ID'} eq $cgiparams{'LOCAL_ID'}) && ($cgiparams{'LOCAL_ID'} ne ''))
) {
$errormessage = $Lang::tr{'invalid local-remote id'} . '<br />' .
# Extract the CA certificate from the file
&General::log("ipsec", "Extracting caroot from p12...");
if (open(STDIN, "-|")) {
- my $opt = " pkcs12 -cacerts -nokeys";
+ my $opt = " pkcs12 -legacy -cacerts -nokeys";
$opt .= " -in $filename";
$opt .= " -out /tmp/newcacert";
$errormessage = &callssl ($opt);
if (!$errormessage) {
&General::log("ipsec", "Extracting host cert from p12...");
if (open(STDIN, "-|")) {
- my $opt = " pkcs12 -clcerts -nokeys";
+ my $opt = " pkcs12 -legacy -clcerts -nokeys";
$opt .= " -in $filename";
$opt .= " -out /tmp/newhostcert";
$errormessage = &callssl ($opt);
while (grep(/Imported-$idx/, @names) ) {$idx++};
$cgiparams{'CA_NAME'}="Imported-$idx";
$cgiparams{'CERT_NAME'}=&Header::cleanhtml(getCNfromcert ('/tmp/newhostcert'));
- move("/tmp/newcacert", "${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem");
- $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0);
+
+ unless(move("/tmp/newcacert", "${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem")) {
+ $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
+ }
+
if (!$errormessage) {
my $key = &General::findhasharraykey (\%cahash);
$cahash{$key}[0] = $cgiparams{'CA_NAME'};
}
if (!$errormessage) {
&General::log("ipsec", "Moving host cert...");
- move("/tmp/newhostcert", "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem");
- $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0);
+ unless(move("/tmp/newhostcert", "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem")) {
+ $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
+ }
}
#cleanup temp files
unlink ($filename);
goto VPNCONF_ERROR;
} else {
- move($filename, "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem");
- if ($? ne 0) {
- $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
+ unless (move($filename, "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem")) {
+ $errormessage = "$Lang::tr{'certificate file move failed'} ($filename): $!";
unlink ($filename);
goto VPNCONF_ERROR;
}
&General::log("ipsec", "Creating a cert...");
if (open(STDIN, "-|")) {
- my $opt = " req -nodes -rand /proc/interrupts:/proc/net/rt_cache";
- $opt .= " -newkey rsa:2048";
+ my $opt = " req -nodes";
+ $opt .= " -newkey rsa:4096";
$opt .= " -keyout ${General::swroot}/certs/$cgiparams{'NAME'}key.pem";
$opt .= " -out ${General::swroot}/certs/$cgiparams{'NAME'}req.pem";
# Create the pkcs12 file
&General::log("ipsec", "Packing a pkcs12 file...");
- $opt = " pkcs12 -export";
+ $opt = " pkcs12 -legacy -export";
$opt .= " -inkey ${General::swroot}/certs/$cgiparams{'NAME'}key.pem";
$opt .= " -in ${General::swroot}/certs/$cgiparams{'NAME'}cert.pem";
$opt .= " -name \"$cgiparams{'NAME'}\"";
#use default advanced value
$cgiparams{'IKE_ENCRYPTION'} = 'chacha20poly1305|aes256gcm128|aes256gcm96|aes256gcm64|aes256|aes192gcm128|aes192gcm96|aes192gcm64|aes192|aes128gcm128|aes128gcm96|aes128gcm64|aes128'; #[18];
$cgiparams{'IKE_INTEGRITY'} = 'sha2_512|sha2_256'; #[19];
- $cgiparams{'IKE_GROUPTYPE'} = 'curve448|curve25519|4096|3072|2048'; #[20];
+ $cgiparams{'IKE_GROUPTYPE'} = 'curve448|curve25519|e521|e384|4096|3072'; #[20];
$cgiparams{'IKE_LIFETIME'} = '3'; #[16];
$cgiparams{'ESP_ENCRYPTION'} = 'chacha20poly1305|aes256gcm128|aes256gcm96|aes256gcm64|aes256|aes192gcm128|aes192gcm96|aes192gcm64|aes192|aes128gcm128|aes128gcm96|aes128gcm64|aes128'; #[21];
$cgiparams{'ESP_INTEGRITY'} = 'sha2_512|sha2_256'; #[22];
- $cgiparams{'ESP_GROUPTYPE'} = 'curve448|curve25519|4096|3072|2048'; #[23];
+ $cgiparams{'ESP_GROUPTYPE'} = 'curve448|curve25519|e521|e384|4096|3072'; #[23];
$cgiparams{'ESP_KEYLIFE'} = '1'; #[17];
$cgiparams{'COMPRESSION'} = 'off'; #[13];
$cgiparams{'ONLY_PROPOSED'} = 'on'; #[24];
<option value='6144' $checked{'IKE_GROUPTYPE'}{'6144'}>MODP-6144</option>
<option value='4096' $checked{'IKE_GROUPTYPE'}{'4096'}>MODP-4096</option>
<option value='3072' $checked{'IKE_GROUPTYPE'}{'3072'}>MODP-3072</option>
- <option value='2048' $checked{'IKE_GROUPTYPE'}{'2048'}>MODP-2048</option>
- <option value='1536' $checked{'IKE_GROUPTYPE'}{'1536'}>MODP-1536</option>
+ <option value='2048' $checked{'IKE_GROUPTYPE'}{'2048'}>MODP-2048 ($Lang::tr{'vpn weak'})</option>
+ <option value='1536' $checked{'IKE_GROUPTYPE'}{'1536'}>MODP-1536 ($Lang::tr{'vpn broken'})</option>
<option value='1024' $checked{'IKE_GROUPTYPE'}{'1024'}>MODP-1024 ($Lang::tr{'vpn broken'})</option>
<option value='768' $checked{'IKE_GROUPTYPE'}{'768'}>MODP-768 ($Lang::tr{'vpn broken'})</option>
</select>
<option value='6144' $checked{'ESP_GROUPTYPE'}{'6144'}>MODP-6144</option>
<option value='4096' $checked{'ESP_GROUPTYPE'}{'4096'}>MODP-4096</option>
<option value='3072' $checked{'ESP_GROUPTYPE'}{'3072'}>MODP-3072</option>
- <option value='2048' $checked{'ESP_GROUPTYPE'}{'2048'}>MODP-2048</option>
- <option value='1536' $checked{'ESP_GROUPTYPE'}{'1536'}>MODP-1536</option>
+ <option value='2048' $checked{'ESP_GROUPTYPE'}{'2048'}>MODP-2048 ($Lang::tr{'vpn weak'})</option>
+ <option value='1536' $checked{'ESP_GROUPTYPE'}{'1536'}>MODP-1536 ($Lang::tr{'vpn broken'})</option>
<option value='1024' $checked{'ESP_GROUPTYPE'}{'1024'}>MODP-1024 ($Lang::tr{'vpn broken'})</option>
<option value='768' $checked{'ESP_GROUPTYPE'}{'768'}>MODP-768 ($Lang::tr{'vpn broken'})</option>
<option value='none' $checked{'ESP_GROUPTYPE'}{'none'}>- $Lang::tr{'none'} -</option>
print "<td align='left' $col> </td>";
}
print "<td align='center' $col>$confighash{$key}[25]</td>";
- my $col1="bgcolor='${Header::colourred}'";
- my $active = "<b><font color='#FFFFFF'>$Lang::tr{'capsclosed'}</font></b>";
+ my $col1="class='status is-disconnected'";
+ my $active = "$Lang::tr{'capsclosed'}";
if ($confighash{$key}[33] eq "add") {
- $col1="bgcolor='${Header::colourorange}'";
- $active = "<b><font color='#FFFFFF'>$Lang::tr{'vpn wait'}</font></b>";
+ $col1="class='status is-connecting'";
+ $active = "$Lang::tr{'vpn wait'}";
}
foreach my $line (@status) {
if (($line =~ /\"$confighash{$key}[1]\".*IPsec SA established/) ||
($line =~ /$confighash{$key}[1]\{.*INSTALLED/)) {
- $col1="bgcolor='${Header::colourgreen}'";
- $active = "<b><font color='#FFFFFF'>$Lang::tr{'capsopen'}</font></b>";
+ $col1="class='status is-connected'";
+ $active = "$Lang::tr{'capsopen'}";
last;
} elsif ($line =~ /$confighash{$key}[1]\[.*CONNECTING/) {
- $col1="bgcolor='${Header::colourorange}'";
- $active = "<b><font color='#FFFFFF'>$Lang::tr{'vpn connecting'}</font></b>";
+ $col1="class='status is-connecting'";
+ $active = "$Lang::tr{'vpn connecting'}";
} elsif ($line =~ /$confighash{$key}[1]\{.*ROUTED/) {
- $col1="bgcolor='${Header::colourorange}'";
- $active = "<b><font color='#FFFFFF'>$Lang::tr{'vpn on-demand'}</font></b>";
+ $col1="class='status is-connecting'";
+ $active = "$Lang::tr{'vpn on-demand'}";
}
}
# move to blue if really down
if ($confighash{$key}[0] eq 'off' && $col1 =~ /${Header::colourred}/ ) {
- $col1="bgcolor='${Header::colourblue}'";
- $active = "<b><font color='#FFFFFF'>$Lang::tr{'capsclosed'}</font></b>";
+ $col1="class='status is-disabled'";
+ $active = "$Lang::tr{'capsclosed'}";
}
print <<END
<td align='center' $col1>$active</td>
<input type='hidden' name='ACTION' value="$Lang::tr{'download host certificate'}" />
</form>
</td>
- <td width='4%' $col2> </td></tr>
+ <td width='4%' align='center' $col2>
+ <form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <input type='image' name='$Lang::tr{'regenerate host certificate'}' src='/images/reload.gif' alt='$Lang::tr{'regenerate host certificate'}' title='$Lang::tr{'regenerate host certificate'}' />
+ <input type='hidden' name='ACTION' value='$Lang::tr{'regenerate host certificate'}' />
+ </form>
+ </td></tr>
END
;
} else {
return join(",", @cidr_nets);
}
+
+sub regenerate_host_certificate() {
+ my $errormessage = "";
+
+ &General::log("ipsec", "Regenerating host certificate...");
+
+ # Create a CSR based on the existing certificate
+ my $opt = " x509 -x509toreq -copy_extensions copyall";
+ $opt .= " -signkey ${General::swroot}/certs/hostkey.pem";
+ $opt .= " -in ${General::swroot}/certs/hostcert.pem";
+ $opt .= " -out ${General::swroot}/certs/hostreq.pem";
+ $errormessage = &callssl($opt);
+
+ # Revoke the old certificate
+ if (!$errormessage) {
+ &General::log("ipsec", "Revoking the old host cert...");
+
+ my $opt = " ca -revoke ${General::swroot}/certs/hostcert.pem";
+ $errormessage = &callssl($opt);
+ }
+
+ # Sign the host certificate request
+ if (!$errormessage) {
+ &General::log("ipsec", "Self signing host cert...");
+
+ my $opt = " ca -md sha256 -days 825";
+ $opt .= " -batch -notext";
+ $opt .= " -in ${General::swroot}/certs/hostreq.pem";
+ $opt .= " -out ${General::swroot}/certs/hostcert.pem";
+ $errormessage = &callssl ($opt);
+
+ unlink ("${General::swroot}/certs/hostreq.pem"); #no more needed
+ }
+
+ # Reload the new certificate
+ if (!$errormessage) {
+ &General::system('/usr/local/bin/ipsecctrl', 'R');
+ }
+
+ return $errormessage;
+}