#!/usr/bin/perl
# geht ueberhaupt nicht
use 5.010;
use strict;
use warnings;

use if $ENV{DEBUG} => "Smart::Comments";
my $pfad = "./CA";


sub menue() {
    my $eg = "";

    while (1) {
	system("clear");
        print
" Willkommen beim SSL-Certificator, Ihrem nuetzlichem Perlprogramm\n zum einfachen erstellen von SSL-Zertifikaten.\n\n\n";
        print " Menue\n\n";
        print
"  n - Neues Root-Zertifikat erstellen\n  r - Request erstellen\n  s - Request signieren\n  w - Zertifikat wiederrufen\n  a - Annulierungsliste erstellen\n\n  q - Beenden\n\n ";
        chomp($eg = <STDIN>);

	given ($eg) {
	    when("q") {	# $eg ~~ "q"
		system('clear');
		exit;
	    }
	    when("n") {
		system('clear');
		&rootca;
	    }
	    default {
	    }
	}

#	SWITCH: {
#	    ($eg eq "q") and do { ….; last SWITCH; }
#	    ($eq eq "n") and do { …; last SWITCH; }
#	}

#        } elsif ($eg eq 's') {
#            system('clear');
#            &sign;
#        } elsif ($eg eq 'r') {
#            system('clear');
#            &request;
#        }
#        if ($eg eq 'w') {
#            system('clear');
#            &revoke;
#        }
#        if ($eg eq 'a') {
#            system('clear');
#            &revlist;
#        }
      }
}

sub rootca {
    my $days;
    my $pk;
    my $rca;
    print " Ihr Zertifikat wird erstellt. Bitte warten Sie.\n";
    print " ...\n ";

    mkdir($_ = "$pfad/newcerts") or die "Can't mkdir $_: $!\n";

    system("mkdir -p $pfad/newcerts");	# mkdir / File::Path::make_path
    system("mkdir -p $pfad/private");

    # system("echo '01' >$pfad/serial");
    {
	open(my $x, ">", "$pfad/serial") or die;
	print $x "01\n";
	close($x);
    }

    #if (-e "$pfad/index.txt") {		    # RACE CONDITION
    #    system("/bin/rm $pfad/index.txt");	    # rm -f
    #}
#    unlink "$pfad/index.txt";
#    system("/bin/touch $pfad/index.txt");
    {
	open(my $x, ">", "$pfad/index.txt");
	close($x);
    }
    open(CONF, ">$pfad/openssl.cnf");
    print CONF
"#\n# OpenSSL configuration file.\n#\n\n# Establish working directory.\n\ndir = $pfad\n\n[ req ]\ndefault_bits\t\t= 1024\t\t# Size of keys\ndefault_keyfile\t\t= key.pem\t\t# name of generated keys\ndefault_md\t\t= md5\t\t# message digest algorithm\nstring_mask\t\t= nombstr\t\t# permitted characters\ndistinguished_name\t= req_distinguished_name\n\n[ req_distinguished_name ]\n# Variable name\t\t\t  Prompt string\n#----------------------\t  ----------------------------------\n0.organizationName\t= Organization Name (company)\norganizationalUnitName\t= Organizational Unit Name (department, division)\nemailAddress\t\t= Email Address\nemailAddress_max\t= 40\nlocalityName\t\t= Locality Name (city, district)\nstateOrProvinceName\t= State or Province Name (full name)\ncountryName\t\t= Country Name (2 letter code)\ncountryName_min\t\t= 2\ncountryName_max\t\t= 2\ncommonName\t\t= Common Name (hostname, IP, or your name)\ncommonName_max\t\t= 64\n\n# Default values for the above, for consistency and less typing.\n# Variable name\t\t\t  Value\n#------------------------------\t  ------------------------------\n0.organizationName_default\t= Your Company\nlocalityName_default\t\t= Your City\nstateOrProvinceName_default\t= Your Province\ncountryName_default\t\t= OO\n\n[ v3_ca ]\nbasicConstraints\t= CA:TRUE\nsubjectKeyIdentifier\t= hash\nauthorityKeyIdentifier\t= keyid:always,issuer:always";
    print CONF <<_EOT;
127.0.0.1	localhost 
127.0.1.1	jumper.schlittermann.de	jumper
212.80.235.130  pu.schlittermann.de ssl.schlittermann.de pu

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
_EOT

    close CONF;
    <STDIN>;
    do {
        system('clear');
        print
          " Wie lange soll das Zertifikat gueltig sein? (Angabe in Tagen)\n ";
        chomp($days = <STDIN>);
    } while ($days !~ m/\d*/);
    system('clear');
    print " Ihr Zertifikat wird $days Tage gueltig sein.\n ";
    system(
"/usr/bin/openssl req -new -x509 -extensions v3_ca -keyout $pfad/private/cakey.pem -out $pfad/cacert.pem -days $days -config $pfad/openssl.cnf"
    );
    <STDIN>;
    do {
        system('clear');
        print
" Moechten Sie sich den Private Key ansehen?\n\n  j - ja\n  n - nein\n\n ";
        chomp($pk = <STDIN>);
        system('clear');
        if ($pk eq 'j') {
            system("/bin/cat $pfad/private/cakey.pem");
            <STDIN>;
        }
    } until ($pk ne 'j' | $pk ne 'n');
    do {
        system('clear');
        print
" Moechten Sie sich das Zertifikat ansehen?\n\n  j - ja\n  n - nein\n\n ";
        chomp($rca = <STDIN>);
        system('clear');
        if ($rca eq 'j') {
            system("/bin/cat $pfad/cacert.pem");
            <STDIN>;
        }
    } until ($rca ne 'j' | $rca ne 'n');
    system('clear');
    &menue;
}

sub request {
    my $egreq;
    my $rootpf;
    my $config;
    my $eg;
    do {
        system('clear');
        print
" Konfigurationsdatei erstellen oder Pfad angeben?\n\n  e - erstellen\n  p - Pfad angeben\n\n ";
        chomp($eg = <STDIN>);
        system('clear');
    } until ($eg ne 'e' | $eg ne 'p');
    if ($eg eq 'e') {
        if (-d $pfad) {
            open(CONF, ">$pfad/openssl.cnf");
            print CONF
"#\n# OpenSSL configuration file.\n#\n\n# Establish working directory.\n\ndir = $pfad\n\n[ req ]\ndefault_bits\t\t= 1024\t\t# Size of keys\ndefault_keyfile\t\t= key.pem\t\t# name of generated keys\ndefault_md\t\t= md5\t\t# message digest algorithm\nstring_mask\t\t= nombstr\t\t# permitted characters\ndistinguished_name\t= req_distinguished_name\nreq_extensions\t\t= v3_req\n\n[ req_distinguished_name ]\n# Variable name\t\t\t  Prompt string\n#----------------------\t  ----------------------------------\n0.organizationName\t= Organization Name (company)\norganizationalUnitName\t= Organizational Unit Name (department, division)\nemailAddress\t\t= Email Address\nemailAddress_max\t= 40\nlocalityName\t\t= Locality Name (city, district)\nstateOrProvinceName\t= State or Province Name (full name)\ncountryName\t\t= Country Name (2 letter code)\ncountryName_min\t\t= 2\ncountryName_max\t\t= 2\ncommonName\t\t= Common Name (hostname, IP, or your name)\ncommonName_max\t\t= 64\n\n# Default values for the above, for consistency and less typing.\n# Variable name\t\t\t  Value\n#------------------------------\t  ------------------------------\n0.organizationName_default\t= Your Company\nlocalityName_default\t\t= Your City\nstateOrProvinceName_default\t= Your Province\ncountryName_default\t\t= OO\n\n[ v3_ca ]\nbasicConstraints\t\t= CA:TRUE\nsubjectKeyIdentifier\t\t= hash\nauthorityKeyIdentifier\t\t= keyid:always,issuer:always\n\n[ v3_req ]\nbasicConstraints\t\t= CA:FALSE\nsubjectKeyIdentifier\t\t= hash";
            close CONF;
        }
        else {
            system("/bin/mkdir $pfad");
            open(CONF, ">$pfad/openssl.cnf");
            print CONF
"#\n# OpenSSL configuration file.\n#\n\n# Establish working directory.\n\ndir = $pfad\n\n[ req ]\ndefault_bits\t\t= 1024\t\t# Size of keys\ndefault_keyfile\t\t= key.pem\t\t# name of generated keys\ndefault_md\t\t= md5\t\t# message digest algorithm\nstring_mask\t\t= nombstr\t\t# permitted characters\ndistinguished_name\t= req_distinguished_name\nreq_extensions\t\t= v3_req\n\n[ req_distinguished_name ]\n# Variable name\t\t\t  Prompt string\n#----------------------\t  ----------------------------------\n0.organizationName\t= Organization Name (company)\norganizationalUnitName\t= Organizational Unit Name (department, division)\nemailAddress\t\t= Email Address\nemailAddress_max\t= 40\nlocalityName\t\t= Locality Name (city, district)\nstateOrProvinceName\t= State or Province Name (full name)\ncountryName\t\t= Country Name (2 letter code)\ncountryName_min\t\t= 2\ncountryName_max\t\t= 2\ncommonName\t\t= Common Name (hostname, IP, or your name)\ncommonName_max\t\t= 64\n\n# Default values for the above, for consistency and less typing.\n# Variable name\t\t\t  Value\n#------------------------------\t  ------------------------------\n0.organizationName_default\t= Your Company\nlocalityName_default\t\t= Your City\nstateOrProvinceName_default\t= Your Province\ncountryName_default\t\t= OO\n\n[ v3_ca ]\nbasicConstraints\t\t= CA:TRUE\nsubjectKeyIdentifier\t\t= hash\nauthorityKeyIdentifier\t\t= keyid:always,issuer:always\n\n[ v3_req ]\nbasicConstraints\t\t= CA:FALSE\nsubjectKeyIdentifier\t\t= hash";
            close CONF;
        }
        print " Konfigurationsdatei erstellt $pfad/openssl.cnf\n ";
        <STDIN>;
    }
    if ($eg eq 'p') {
        system('clear');
        print " Bitte geben Sie den Pfad zu Ihrer Konfigurationsdatei an.\n ";
        chomp($config = <STDIN>);
        system('clear');
        print
" Bitte achten Sie darauf, dass sie den Common Name aendern, sodass er zu Ihrer Domain passt.\n Bsp.:\n\n Domain: hostname.domainname\n         secure.yourdomain.de\n\n ";
	system("openssl", $pfad)
        system(openssl => qw(req -new -nodes),  
	    -out => "$pfad/req.pem", 
	    -config => $config);
    }
    else {
        system('clear');
        print
" Bitte achten Sie darauf, dass sie den Common Name aendern, sodass er zu Ihrer Domain passt.\n Bsp.:\n\n Domain: hostname.domainname\n         secure.yourdomain.de ";
        system(
"/usr/bin/openssl req -new -nodes -out $pfad/req.pem -config $pfad/openssl.cnf"
        );
    }
    <STDIN>;
    do {
        system('clear');
        print " Request ueberpruefen?\n\n  j - ja\n  n - nein\n\n ";
        chomp($egreq = <STDIN>);
        if ($egreq eq 'j') {
            system('clear');
            system(
                "/usr/bin/openssl req -in $pfad/req.pem -text -verify -noout");
            <STDIN>;
        }
    } until ($egreq ne 'j' | $egreq ne 'n');
    system('clear');
    &menue;
}

sub sign {
    my $eg;
    open(CONF, ">$pfad/openssl.cnf");
    print CONF
"#\n# OpenSSL configuration file.\n#\n\n# Establish working directory.\n\ndir = $pfad\n\n[ ca ]\ndefault_ca\t\t= CA_default\n\n[ CA_default ]\nserial\t\t\t= \$dir/serial\ndatabase\t\t= \$dir/index.txt\nnew_certs_dir\t\t= \$dir/newcerts\ncertificate\t\t= \$dir/cacert.pem\nprivate_key\t\t= \$dir/private/cakey.pem\ndefault_days\t\t= 365\ndefault_md\t\t= md5\npreserve\t\t= no\nemail_in_dn\t\t= no\nnameopt\t\t\t= default_ca\ncertopt\t\t\t= default_ca\npolicy\t\t\t= policy_match\n\n[ policy_match ]\ncountryName\t\t= match\nstateOrProvinceName\t= match\norganizationName\t= match\norganizationalUnitName\t= optional\ncommonName\t\t= supplied\nemailAddress\t\t= optional\n\n[ req ]\ndefault_bits\t\t= 1024\t\t# Size of keys\ndefault_keyfile\t\t= key.pem\t\t# name of generated keys\ndefault_md\t\t= md5\t\t# message digest algorithm\nstring_mask\t\t= nombstr\t\t# permitted characters\ndistinguished_name\t= req_distinguished_name\nreq_extensions\t\t= v3_req\n\n[ req_distinguished_name ]\n# Variable name\t\t\t  Prompt string\n#----------------------\t  ----------------------------------\n0.organizationName\t= Organization Name (company)\norganizationalUnitName\t= Organizational Unit Name (department, division)\nemailAddress\t\t= Email Address\nemailAddress_max\t= 40\nlocalityName\t\t= Locality Name (city, district)\nstateOrProvinceName\t= State or Province Name (full name)\ncountryName\t\t= Country Name (2 letter code)\ncountryName_min\t\t= 2\ncountryName_max\t\t= 2\ncommonName\t\t= Common Name (hostname, IP, or your name)\ncommonName_max\t\t= 64\n\n# Default values for the above, for consistency and less typing.\n# Variable name\t\t\t  Value\n#------------------------------\t  ------------------------------\n0.organizationName_default\t= Your Company\nlocalityName_default\t\t= Your City\nstateOrProvinceName_default\t= Your Province\ncountryName_default\t\t= OO\n\n[ v3_ca ]\nbasicConstraints\t\t= CA:TRUE\nsubjectKeyIdentifier\t\t= hash\nauthorityKeyIdentifier\t\t= keyid:always,issuer:always\n[ v3_req ]\nbasicConstraints\t\t= CA:FALSE\nsubjectKeyIdentifier\t\t= hash";
    system(
"/usr/bin/openssl ca -out $pfad/cert.pem -config $pfad/openssl.cnf -infiles $pfad/req.pem"
    );
    print "Zertifikat wurde unterzeichnet";
    <STDIN>;
    do {
        system('clear');
        print "Zertifikat ueberpruefen?\n\n  j - ja\n  n - nein\n\n";
        chomp($eg = <STDIN>);
        if ($eg eq 'j') {
            system(
"/usr/bin/openssl x509 -in $pfad/cert.pem -noout -text -purpose | /bin/more"
            );
            <STDIN>;
        }
    } until ($eg ne 'j' | $eg ne 'n');
    $eg = '';
    do {
        system('clear');
        print
"Sollen die lesbaren Elemente aus dem Zertifikat entfernt werden?\n\n  j - ja\n  n - nein\n\n";
        chomp($eg = <STDIN>);
        if ($eg eq 'j') {
            print "...\n";
	    # rename()
	    # File::Copy
            system("/bin/mv $pfad/cert.pem $pfad/tmp.pem");
            system(
                "/usr/bin/openssl x509 -in $pfad/tmp.pem -out $pfad/cert.pem");
            print "Alle lesbaren Elemente wurden entfernt.";
            <STDIN>;
        }
    } until ($eg ne 'j' | $eg ne 'n');
    &menue;
}

sub revoke {
    my $eg;
    do {
        print
"Welches Zertifikat soll wiederrufen werden?\nFuer Informationen zu allen Zertifikaten, schauen\nSie in die Datei index.txt.\n";
        print "Datei öffnen?\n\nj - ja\nn - nein\n\n";
        chomp($eg = <STDIN>);
        if ($eg eq 'j') {
            open(INDEX, "<$pfad/index.txt");
            my @index = <INDEX>;
            print sort @index;
            <STDIN>;
        }
    } until ($eg eq 'j' | $eg eq 'n');
    print
"Welches Zertifikat soll wiederrufen werden?\n(Geben Sie die 2-stellige Nummer ein)\n";
    chomp($eg = <STDIN>);
    system(
"/usr/bin/openssl ca -revoke $pfad/newcerts/$eg.pem -config $pfad/openssl.cnf"
    );
    print "Zertifikat $eg wiederrufen.";
    <STDIN>;
    &menue;
}

sub revlist {
    system(
"/usr/bin/openssl ca -gencrl -crldays 31 -config $pfad/openssl.cnf -out $pfad/rootca.crl"
    );
    print "Certicate Revocation List erstellt";
    <STDIN>;
    &menue;
}

sub main(@) {
    menue();
    exit 0;
}

main(@ARGV);
