+ #cleanup temp files
+ unlink ($filename);
+ unlink ('/tmp/newcacert');
+ unlink ('/tmp/newhostcert');
+ unlink ('/tmp/newhostkey');
+ if ($errormessage) {
+ unlink ("${General::swroot}/ca/cacert.pem");
+ unlink ("${General::swroot}/certs/hostcert.pem");
+ unlink ("${General::swroot}/certs/hostkey.pem");
+ goto ROOTCERT_ERROR;
+ }
+
+ # Create empty CRL cannot be done because we don't have
+ # the private key for this CAROOT
+ # IPFire can only import certificates
+
+ &General::log("ipsec", "p12 import completed!");
+ &cleanssldatabase();
+ goto ROOTCERT_SUCCESS;
+
+ } elsif ($cgiparams{'ROOTCERT_COUNTRY'} ne '') {
+
+ # Validate input since the form was submitted
+ if ($cgiparams{'ROOTCERT_ORGANIZATION'} eq ''){
+ $errormessage = $Lang::tr{'organization cant be empty'};
+ goto ROOTCERT_ERROR;
+ }
+ if (length($cgiparams{'ROOTCERT_ORGANIZATION'}) >60) {
+ $errormessage = $Lang::tr{'organization too long'};
+ goto ROOTCERT_ERROR;
+ }
+ if ($cgiparams{'ROOTCERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
+ $errormessage = $Lang::tr{'invalid input for organization'};
+ goto ROOTCERT_ERROR;
+ }
+ if ($cgiparams{'ROOTCERT_HOSTNAME'} eq ''){
+ $errormessage = $Lang::tr{'hostname cant be empty'};
+ goto ROOTCERT_ERROR;
+ }
+ unless (&General::validfqdn($cgiparams{'ROOTCERT_HOSTNAME'}) || &General::validip($cgiparams{'ROOTCERT_HOSTNAME'})) {
+ $errormessage = $Lang::tr{'invalid input for hostname'};
+ goto ROOTCERT_ERROR;
+ }
+ if ($cgiparams{'ROOTCERT_EMAIL'} ne '' && (! &General::validemail($cgiparams{'ROOTCERT_EMAIL'}))) {
+ $errormessage = $Lang::tr{'invalid input for e-mail address'};
+ goto ROOTCERT_ERROR;
+ }
+ if (length($cgiparams{'ROOTCERT_EMAIL'}) > 40) {
+ $errormessage = $Lang::tr{'e-mail address too long'};
+ goto ROOTCERT_ERROR;
+ }
+ if ($cgiparams{'ROOTCERT_OU'} ne '' && $cgiparams{'ROOTCERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
+ $errormessage = $Lang::tr{'invalid input for department'};
+ goto ROOTCERT_ERROR;
+ }
+ if ($cgiparams{'ROOTCERT_CITY'} ne '' && $cgiparams{'ROOTCERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
+ $errormessage = $Lang::tr{'invalid input for city'};
+ goto ROOTCERT_ERROR;
+ }
+ if ($cgiparams{'ROOTCERT_STATE'} ne '' && $cgiparams{'ROOTCERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
+ $errormessage = $Lang::tr{'invalid input for state or province'};
+ goto ROOTCERT_ERROR;
+ }
+ if ($cgiparams{'ROOTCERT_COUNTRY'} !~ /^[A-Z]*$/) {
+ $errormessage = $Lang::tr{'invalid input for country'};
+ goto ROOTCERT_ERROR;
+ }
+ #the exact syntax is a list comma separated of
+ # email:any-validemail
+ # URI: a uniform resource indicator
+ # DNS: a DNS domain name
+ # RID: a registered OBJECT IDENTIFIER
+ # IP: an IP address
+ # example: email:franck@foo.com,IP:10.0.0.10,DNS:franck.foo.com
+
+ if ($cgiparams{'SUBJECTALTNAME'} ne '' && $cgiparams{'SUBJECTALTNAME'} !~ /^(email|URI|DNS|RID|IP):[a-zA-Z0-9 :\/,\.\-_@]*$/) {
+ $errormessage = $Lang::tr{'vpn altname syntax'};
+ goto VPNCONF_ERROR;
+ }
+
+ # Copy the cgisettings to vpnsettings and save the configfile
+ $vpnsettings{'ROOTCERT_ORGANIZATION'} = $cgiparams{'ROOTCERT_ORGANIZATION'};
+ $vpnsettings{'ROOTCERT_HOSTNAME'} = $cgiparams{'ROOTCERT_HOSTNAME'};
+ $vpnsettings{'ROOTCERT_EMAIL'} = $cgiparams{'ROOTCERT_EMAIL'};
+ $vpnsettings{'ROOTCERT_OU'} = $cgiparams{'ROOTCERT_OU'};
+ $vpnsettings{'ROOTCERT_CITY'} = $cgiparams{'ROOTCERT_CITY'};
+ $vpnsettings{'ROOTCERT_STATE'} = $cgiparams{'ROOTCERT_STATE'};
+ $vpnsettings{'ROOTCERT_COUNTRY'} = $cgiparams{'ROOTCERT_COUNTRY'};
+ &General::writehash("${General::swroot}/vpn/settings", \%vpnsettings);
+
+ # Replace empty strings with a .
+ (my $ou = $cgiparams{'ROOTCERT_OU'}) =~ s/^\s*$/\./;
+ (my $city = $cgiparams{'ROOTCERT_CITY'}) =~ s/^\s*$/\./;
+ (my $state = $cgiparams{'ROOTCERT_STATE'}) =~ s/^\s*$/\./;
+
+ # Create the CA certificate
+ if (!$errormessage) {
+ &General::log("ipsec", "Creating cacert...");
+ if (open(STDIN, "-|")) {
+ my $opt = " req -x509 -sha256 -nodes";
+ $opt .= " -days 999999";
+ $opt .= " -newkey rsa:4096";
+ $opt .= " -keyout ${General::swroot}/private/cakey.pem";
+ $opt .= " -out ${General::swroot}/ca/cacert.pem";
+
+ $errormessage = &callssl ($opt);
+ } else { #child
+ print "$cgiparams{'ROOTCERT_COUNTRY'}\n";
+ print "$state\n";
+ print "$city\n";
+ print "$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
+ print "$ou\n";
+ print "$cgiparams{'ROOTCERT_ORGANIZATION'} CA\n";
+ print "$cgiparams{'ROOTCERT_EMAIL'}\n";
+ exit (0);
+ }
+ }
+
+ # Create the Host certificate request
+ if (!$errormessage) {
+ &General::log("ipsec", "Creating host cert...");
+ if (open(STDIN, "-|")) {
+ my $opt = " req -sha256 -nodes";
+ $opt .= " -newkey rsa:2048";
+ $opt .= " -keyout ${General::swroot}/certs/hostkey.pem";
+ $opt .= " -out ${General::swroot}/certs/hostreq.pem";
+ $errormessage = &callssl ($opt);
+ } else { #child
+ print "$cgiparams{'ROOTCERT_COUNTRY'}\n";
+ print "$state\n";
+ print "$city\n";
+ print "$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
+ print "$ou\n";
+ print "$cgiparams{'ROOTCERT_HOSTNAME'}\n";
+ print "$cgiparams{'ROOTCERT_EMAIL'}\n";
+ print ".\n";
+ print ".\n";
+ exit (0);
+ }
+ }
+
+ # Sign the host certificate request
+ if (!$errormessage) {
+ &General::log("ipsec", "Self signing host cert...");
+
+ #No easy way for specifying the contain of subjectAltName without writing a config file...
+ my ($fh, $v3extname) = tempfile ('/tmp/XXXXXXXX');
+ print $fh <<END
+ basicConstraints=CA:FALSE
+ nsComment="OpenSSL Generated Certificate"
+ subjectKeyIdentifier=hash
+ authorityKeyIdentifier=keyid,issuer:always
+ extendedKeyUsage = serverAuth
+END
+;
+ print $fh "subjectAltName=$cgiparams{'SUBJECTALTNAME'}" if ($cgiparams{'SUBJECTALTNAME'});
+ close ($fh);
+
+ my $opt = " ca -md sha256 -days 999999";
+ $opt .= " -batch -notext";
+ $opt .= " -in ${General::swroot}/certs/hostreq.pem";
+ $opt .= " -out ${General::swroot}/certs/hostcert.pem";
+ $opt .= " -extfile $v3extname";
+ $errormessage = &callssl ($opt);
+ unlink ("${General::swroot}/certs/hostreq.pem"); #no more needed
+ unlink ($v3extname);
+ }
+
+ # Create an empty CRL
+ if (!$errormessage) {
+ &General::log("ipsec", "Creating emptycrl...");
+ my $opt = " ca -gencrl";
+ $opt .= " -out ${General::swroot}/crls/cacrl.pem";
+ $errormessage = &callssl ($opt);
+ }
+
+ # Successfully build CA / CERT!
+ if (!$errormessage) {
+ &cleanssldatabase();
+ goto ROOTCERT_SUCCESS;
+ }
+
+ #Cleanup
+ unlink ("${General::swroot}/ca/cacert.pem");
+ unlink ("${General::swroot}/certs/hostkey.pem");
+ unlink ("${General::swroot}/certs/hostcert.pem");
+ unlink ("${General::swroot}/crls/cacrl.pem");
+ &cleanssldatabase();
+ }
+
+ ROOTCERT_ERROR:
+ &Header::showhttpheaders();
+ &Header::openpage($Lang::tr{'ipsec'}, 1, '');
+ &Header::openbigbox('100%', 'left', '', $errormessage);
+ if ($errormessage) {
+ &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
+ print "<class name='base'>$errormessage";
+ print " </class>";
+ &Header::closebox();
+ }
+ &Header::openbox('100%', 'left', "$Lang::tr{'generate root/host certificates'}:");
+ print <<END
+ <form method='post' enctype='multipart/form-data' action='$ENV{'SCRIPT_NAME'}'>
+ <table width='100%' border='0' cellspacing='1' cellpadding='0'>
+ <tr><td width='40%' class='base'>$Lang::tr{'organization name'}: <img src='/blob.gif' alt='*' /></td>
+ <td width='60%' class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_ORGANIZATION' value='$cgiparams{'ROOTCERT_ORGANIZATION'}' size='32' /></td></tr>
+ <tr><td class='base'>$Lang::tr{'ipfires hostname'}: <img src='/blob.gif' alt='*' /></td>
+ <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_HOSTNAME' value='$cgiparams{'ROOTCERT_HOSTNAME'}' size='32' /></td></tr>
+ <tr><td class='base'>$Lang::tr{'your e-mail'}:</td>
+ <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_EMAIL' value='$cgiparams{'ROOTCERT_EMAIL'}' size='32' /></td></tr>
+ <tr><td class='base'>$Lang::tr{'your department'}:</td>
+ <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_OU' value='$cgiparams{'ROOTCERT_OU'}' size='32' /></td></tr>
+ <tr><td class='base'>$Lang::tr{'city'}:</td>
+ <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_CITY' value='$cgiparams{'ROOTCERT_CITY'}' size='32' /></td></tr>
+ <tr><td class='base'>$Lang::tr{'state or province'}:</td>
+ <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_STATE' value='$cgiparams{'ROOTCERT_STATE'}' size='32' /></td></tr>
+ <tr><td class='base'>$Lang::tr{'country'}:</td>
+ <td class='base'><select name='ROOTCERT_COUNTRY'>
+END
+;
+ foreach my $country (sort keys %{Countries::countries}) {
+ print "<option value='$Countries::countries{$country}'";
+ if ( $Countries::countries{$country} eq $cgiparams{'ROOTCERT_COUNTRY'} ) {
+ print " selected='selected'";
+ }
+ print ">$country</option>";
+ }
+ print <<END
+ </select></td></tr>
+ <tr><td class='base'>$Lang::tr{'vpn subjectaltname'} (subjectAltName=email:*,URI:*,DNS:*,RID:*)</td>
+ <td class='base' nowrap='nowrap'><input type='text' name='SUBJECTALTNAME' value='$cgiparams{'SUBJECTALTNAME'}' size='32' /></td></tr>
+ <tr><td> </td>
+ <td><br /><input type='submit' name='ACTION' value='$Lang::tr{'generate root/host certificates'}' /><br /><br /></td></tr>
+ <tr><td class='base' colspan='2' align='left'>
+ <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>:
+ $Lang::tr{'generating the root and host certificates may take a long time. it can take up to several minutes on older hardware. please be patient'}
+ </td></tr>
+ <tr><td colspan='2'><hr></td></tr>
+ <tr><td class='base' nowrap='nowrap'>$Lang::tr{'upload p12 file'}:</td>
+ <td nowrap='nowrap'><input type='file' name='FH' size='32' /></td></tr>
+ <tr><td class='base'>$Lang::tr{'pkcs12 file password'}:</td>
+ <td class='base' nowrap='nowrap'><input type='password' name='P12_PASS' value='$cgiparams{'P12_PASS'}' size='32' /></td></tr>
+ <tr><td> </td>
+ <td><input type='submit' name='ACTION' value='$Lang::tr{'upload p12 file'}' /></td></tr>
+ <tr><td class='base' colspan='2' align='left'>
+ <img src='/blob.gif' alt='*' /> $Lang::tr{'required field'}</td></tr>
+ </table></form>
+END
+;