]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - html/cgi-bin/vpnmain.cgi
suricata: Change midstream policy to "pass-flow"
[people/pmueller/ipfire-2.x.git] / html / cgi-bin / vpnmain.cgi
index 20ee6da93f0053f4224acd12e22c1e594f32735a..9173a85d847f5e17e1b0389144a00fd95c3e7e6c 100644 (file)
@@ -2,7 +2,7 @@
 ###############################################################################
 #                                                                             #
 # 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        #
@@ -193,7 +193,7 @@ sub cleanssldatabase {
                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");
@@ -208,10 +208,13 @@ sub newcleanssldatabase {
                close FILE;
        }
        if (! -s ">${General::swroot}/certs/index.txt") {
-               system ("touch ${General::swroot}/certs/index.txt");
+               open(FILE, ">${General::swroot}/certs/index.txt");
+               close(FILE);
        }
        if (! -s ">${General::swroot}/certs/index.txt.attr") {
-               system ("touch ${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");
        unlink ("${General::swroot}/certs/index.txt.attr.old");
@@ -226,13 +229,14 @@ sub callssl ($) {
        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" : '' ;
 }
 ###
@@ -241,7 +245,7 @@ sub callssl ($) {
 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 = /;
@@ -568,9 +572,9 @@ if ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'TYPE'} eq '' && $cg
        &General::writehash("${General::swroot}/vpn/settings", \%vpnsettings);
        &writeipsecfiles();
        if (&vpnenabled) {
-               system('/usr/local/bin/ipsecctrl', 'S');
+               &General::system('/usr/local/bin/ipsecctrl', 'S');
        } else {
-               system('/usr/local/bin/ipsecctrl', 'D');
+               &General::system('/usr/local/bin/ipsecctrl', 'D');
        }
        sleep $sleepDelay;
        SAVE_ERROR:
@@ -595,7 +599,7 @@ if ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'TYPE'} eq '' && $cg
        }
        &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
        &writeipsecfiles();
-       system('/usr/local/bin/ipsecctrl', 'R');
+       &General::system('/usr/local/bin/ipsecctrl', 'R');
        sleep $sleepDelay;
 
 ###
@@ -673,8 +677,7 @@ END
                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;
@@ -686,7 +689,7 @@ END
        $cahash{$key}[1] = &Header::cleanhtml(getsubjectfromcert ("${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem"));
        &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash);
 
-       system('/usr/local/bin/ipsecctrl', 'R');
+       &General::system('/usr/local/bin/ipsecctrl', 'R');
        sleep $sleepDelay;
 
        UPLOADCA_ERROR:
@@ -702,8 +705,8 @@ END
                &Header::openpage($Lang::tr{'ipsec'}, 1, '');
                &Header::openbigbox('100%', 'left', '', '');
                &Header::openbox('100%', 'left', "$Lang::tr{'ca certificate'}:");
-               my $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem`;
-               $output = &Header::cleanhtml($output,"y");
+               my @output = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
+               my $output = &Header::cleanhtml(join("", @output) ,"y");
                print "<pre>$output</pre>\n";
                &Header::closebox();
                print "<div align='center'><a href='/cgi-bin/vpnmain.cgi'>$Lang::tr{'back'}</a></div>";
@@ -724,7 +727,9 @@ END
                print "Content-Type: application/force-download\n";
                print "Content-Type: application/octet-stream\r\n";
                print "Content-Disposition: attachment; filename=$cahash{$cgiparams{'KEY'}}[0]cert.pem\r\n\r\n";
-               print `/usr/bin/openssl x509 -in ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem`;
+
+               my @cert = &General::system_output("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
+               print "@cert";
                exit(0);
        } else {
                $errormessage = $Lang::tr{'invalid key'};
@@ -739,21 +744,21 @@ END
 
        if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
                foreach my $key (keys %confighash) {
-                       my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem ${General::swroot}/certs/$confighash{$key}[1]cert.pem`;
-                       if ($test =~ /: OK/) {
+                       my @test = &General::system_output("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem", "${General::swroot}/certs/$confighash{$key}[1]cert.pem");
+                       if (grep(/: OK/, @test)) {
                                # Delete connection
                                unlink ("${General::swroot}/certs/$confighash{$key}[1]cert.pem");
                                unlink ("${General::swroot}/certs/$confighash{$key}[1].p12");
                                delete $confighash{$key};
                                &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
                                &writeipsecfiles();
-                               system('/usr/local/bin/ipsecctrl', 'D', $key) if (&vpnenabled);
+                               &General::system('/usr/local/bin/ipsecctrl', 'D', $key) if (&vpnenabled);
                        }
                }
                unlink ("${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
                delete $cahash{$cgiparams{'KEY'}};
                &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash);
-               system('/usr/local/bin/ipsecctrl', 'R');
+               &General::system('/usr/local/bin/ipsecctrl', 'R');
                sleep $sleepDelay;
        } else {
                $errormessage = $Lang::tr{'invalid key'};
@@ -768,8 +773,8 @@ END
        my $assignedcerts = 0;
        if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
                foreach my $key (keys %confighash) {
-                       my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem ${General::swroot}/certs/$confighash{$key}[1]cert.pem`;
-                       if ($test =~ /: OK/) {
+                       my @test = &General::system_output("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem", "${General::swroot}/certs/$confighash{$key}[1]cert.pem");
+                       if (grep(/: OK/, @test)) {
                                $assignedcerts++;
                        }
                }
@@ -805,7 +810,7 @@ END
                        unlink ("${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
                        delete $cahash{$cgiparams{'KEY'}};
                        &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash);
-                       system('/usr/local/bin/ipsecctrl', 'R');
+                       &General::system('/usr/local/bin/ipsecctrl', 'R');
                        sleep $sleepDelay;
                }
        } else {
@@ -817,18 +822,18 @@ END
 ###
 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show root certificate'} ||
        $cgiparams{'ACTION'} eq $Lang::tr{'show host certificate'}) {
-       my $output;
+       my @output;
        &Header::showhttpheaders();
        &Header::openpage($Lang::tr{'ipsec'}, 1, '');
        &Header::openbigbox('100%', 'left', '', '');
        if ($cgiparams{'ACTION'} eq $Lang::tr{'show root certificate'}) {
                &Header::openbox('100%', 'left', "$Lang::tr{'root certificate'}:");
-               $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/ca/cacert.pem`;
+               @output = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ca/cacert.pem");
        } else {
                &Header::openbox('100%', 'left', "$Lang::tr{'host certificate'}:");
-               $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/certs/hostcert.pem`;
+               @output = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/certs/hostcert.pem");
        }
-       $output = &Header::cleanhtml($output,"y");
+       my $output = &Header::cleanhtml(join("", @output) ,"y");
        print "<pre>$output</pre>\n";
        &Header::closebox();
        print "<div align='center'><a href='/cgi-bin/vpnmain.cgi'>$Lang::tr{'back'}</a></div>";
@@ -843,7 +848,9 @@ END
        if ( -f "${General::swroot}/ca/cacert.pem" ) {
                print "Content-Type: application/force-download\n";
                print "Content-Disposition: attachment; filename=cacert.pem\r\n\r\n";
-               print `/usr/bin/openssl x509 -in ${General::swroot}/ca/cacert.pem`;
+
+               my @cert = &General::system_output("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ca/cacert.pem");
+               print join("", @cert);
                exit(0);
        }
 ###
@@ -853,15 +860,25 @@ END
        if ( -f "${General::swroot}/certs/hostcert.pem" ) {
                print "Content-Type: application/force-download\n";
                print "Content-Disposition: attachment; filename=hostcert.pem\r\n\r\n";
-               print `/usr/bin/openssl x509 -in ${General::swroot}/certs/hostcert.pem`;
+
+               my @cert = &General::system_output("/usr/bin/openssl", "x509", "-in", "${General::swroot}/certs/hostcert.pem");
+               print join("", @cert);
                exit(0);
        }
 ###
+### Regenerate the host certificate
+###
+} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'regenerate host certificate'}) {
+       $errormessage = &regenerate_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;
@@ -900,7 +917,7 @@ END
                # 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);
@@ -913,7 +930,7 @@ END
                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);
@@ -927,7 +944,7 @@ END
                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);
@@ -939,20 +956,23 @@ END
 
                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
@@ -1083,7 +1103,7 @@ END
                        &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);
@@ -1216,7 +1236,7 @@ END
 
        ROOTCERT_SUCCESS:
        if (&vpnenabled) {
-               system('/usr/local/bin/ipsecctrl', 'S');
+               &General::system('/usr/local/bin/ipsecctrl', 'S');
                sleep $sleepDelay;
        }
        ROOTCERT_SKIP:
@@ -1228,7 +1248,12 @@ END
        print "Content-Type: application/force-download\n";
        print "Content-Disposition: attachment; filename=" . $confighash{$cgiparams{'KEY'}}[1] . ".p12\r\n";
        print "Content-Type: application/octet-stream\r\n\r\n";
-       print `/bin/cat ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1].p12`;
+
+       open(FILE, "${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
+       my @p12 = <FILE>;
+       close(FILE);
+       print join("", @p12);
+
        exit (0);
 
 # Export Apple profile to browser
@@ -1507,8 +1532,8 @@ END
                &Header::openpage($Lang::tr{'ipsec'}, 1, '');
                &Header::openbigbox('100%', 'left', '', '');
                &Header::openbox('100%', 'left', "$Lang::tr{'cert'}:");
-               my $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem`;
-               $output = &Header::cleanhtml($output,"y");
+               my @output = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
+               my $output = &Header::cleanhtml(join("", @output) ,"y");
                print "<pre>$output</pre>\n";
                &Header::closebox();
                print "<div align='center'><a href='/cgi-bin/vpnmain.cgi'>$Lang::tr{'back'}</a></div>";
@@ -1526,7 +1551,12 @@ END
        if ( -f "${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") {
                print "Content-Type: application/force-download\n";
                print "Content-Disposition: attachment; filename=" . $confighash{$cgiparams{'KEY'}}[1] . "cert.pem\n\n";
-               print `/bin/cat ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem`;
+
+               open(FILE, "${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
+               my @pem = <FILE>;
+               close(FILE);
+               print "@pem";
+
                exit (0);
        }
 
@@ -1543,12 +1573,12 @@ END
                        $confighash{$cgiparams{'KEY'}}[0] = 'on';
                        &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
                        &writeipsecfiles();
-                       system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'}) if (&vpnenabled);
+                       &General::system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'}) if (&vpnenabled);
                } else {
                        $confighash{$cgiparams{'KEY'}}[0] = 'off';
                        &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
                        &writeipsecfiles();
-                       system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'}) if (&vpnenabled);
+                       &General::system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'}) if (&vpnenabled);
                }
                sleep $sleepDelay;
        } else {
@@ -1564,7 +1594,7 @@ END
 
        if ($confighash{$cgiparams{'KEY'}}) {
                if (&vpnenabled) {
-                       system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'});
+                       &General::system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'});
                        sleep $sleepDelay;
                }
        } else {
@@ -1584,7 +1614,7 @@ END
                delete $confighash{$cgiparams{'KEY'}};
                &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
                &writeipsecfiles();
-               system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'}) if (&vpnenabled);
+               &General::system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'}) if (&vpnenabled);
        } else {
                $errormessage = $Lang::tr{'invalid key'};
        }
@@ -1919,7 +1949,7 @@ END
                # 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);
@@ -1932,7 +1962,7 @@ END
                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);
@@ -1952,8 +1982,8 @@ END
                                unshift (@names,$cahash{$x}[0]);
                        }
                        if ($casubject) { # a new one!
-                               my $temp = `/usr/bin/openssl x509 -text -in /tmp/newcacert`;
-                               if ($temp !~ /CA:TRUE/i) {
+                               my @temp = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "/tmp/newcacert");
+                               if (! grep(/CA:TRUE/, @temp)) {
                                        $errormessage = $Lang::tr{'not a valid ca certificate'};
                                } else {
                                        #compute a name for it
@@ -1961,22 +1991,26 @@ END
                                        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'};
                                                $cahash{$key}[1] = $casubject;
                                                &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash);
-                                               system('/usr/local/bin/ipsecctrl', 'R');
+                                               &General::system('/usr/local/bin/ipsecctrl', 'R');
                                        }
                                }
                        }
                }
                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
@@ -2008,12 +2042,12 @@ END
                # Verify the certificate has a valid CA and move it
                &General::log("ipsec", "Validating imported cert against our known CA...");
                my $validca = 1; #assume ok
-               my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/cacert.pem $filename`;
-               if ($test !~ /: OK/) {
+               my @test = &General::system_output("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ca/cacert.pem", "$filename");
+               if (! grep(/: OK/, @test)) {
                        my $validca = 0;
                        foreach my $key (keys %cahash) {
-                               $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$key}[0]cert.pem $filename`;
-                               if ($test =~ /: OK/) {
+                               @test = &General::system_output("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ca/$cahash{$key}[0]cert.pem", "$filename");
+                               if (grep(/: OK/, @test)) {
                                        $validca = 1;
                                        last;
                                }
@@ -2024,9 +2058,8 @@ END
                        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;
                        }
@@ -2115,8 +2148,8 @@ END
                &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";
 
@@ -2174,7 +2207,7 @@ END
 
                # 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'}\"";
@@ -2276,7 +2309,7 @@ END
        &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
        &writeipsecfiles();
        if (&vpnenabled) {
-               system('/usr/local/bin/ipsecctrl', 'S', $key);
+               &General::system('/usr/local/bin/ipsecctrl', 'S', $key);
                sleep $sleepDelay;
        }
        if ($cgiparams{'EDIT_ADVANCED'} eq 'on') {
@@ -2337,11 +2370,11 @@ END
        #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];
@@ -2822,7 +2855,7 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
                &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
                &writeipsecfiles();
                if (&vpnenabled) {
-                       system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'});
+                       &General::system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'});
                        sleep $sleepDelay;
                }
                goto ADVANCED_END;
@@ -3123,8 +3156,8 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
                                        <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>
@@ -3146,8 +3179,8 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
                                        <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>
@@ -3271,7 +3304,7 @@ EOF
        &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
        $cgiparams{'CA_NAME'} = '';
 
-       my @status = `/usr/local/bin/ipsecctrl I 2>/dev/null`;
+       my @status = &General::system_output("/usr/local/bin/ipsecctrl", "I");
 
        $checked{'ENABLED'} = $cgiparams{'ENABLED'} eq 'on' ? "checked='checked'" : '';
 
@@ -3585,7 +3618,12 @@ END
                        <input type='hidden' name='ACTION' value="$Lang::tr{'download host certificate'}" />
                        </form>
                </td>
-               <td width='4%' $col2>&nbsp;</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 {
@@ -3755,3 +3793,44 @@ sub make_subnets($$) {
 
        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;
+}