diff --git a/CommModule/readme.txt b/CommModule/readme.txt index d832491..94f09fe 100644 --- a/CommModule/readme.txt +++ b/CommModule/readme.txt @@ -3,4 +3,5 @@ commdaemon Script to run client.pl or server.pl commmodule Script for startup/shutdown of CommModule from /etc/init.d logclean.sh Maintenance script for logfiles generated by CommModule serial.conf Serial Port configuration file +server.pl The real server, running on the signing server usbclient.pl Obsoleted USB version of client.pl above diff --git a/CommModule/server.pl b/CommModule/server.pl new file mode 100755 index 0000000..eb5113a --- /dev/null +++ b/CommModule/server.pl @@ -0,0 +1,1045 @@ +#!/usr/bin/perl -w + +# (c) 2006-2007 by CAcert.org + +# Server (running on the certificate machine) + +use strict; +use Device::SerialPort qw( :PARAM :STAT 0.07 ); +use POSIX; +use IO::Select; +use File::CounterFile; +use Time::HiRes q(usleep); +use IPC::Open3; +use File::Copy; +use Digest::SHA1 qw(sha1_hex); + +#Protocol version: +my $ver=1; + +my $debug=0; + +my $paranoid=1; + +my $serialport="/dev/ttyUSB0"; +#my $serialport="/dev/ttyS0"; + +my $CPSUrl="http://www.cacert.org/cps.php"; + +my $OCSPUrl="http://ocsp.cacert.org/"; + +my $gpgbin="/usr/bin/gpg"; + +my $opensslbin="/usr/bin/openssl"; + +my $work="./work"; + +#my $gpgID='gpgtest@cacert.at'; +my $gpgID='gpg@cacert.org'; + + +my %PkiSystems=( +"1"=>"X.509", +"2"=>"OpenPGP"); +my %rootkeys=( +"1"=>5, #X.509 +"2"=>1);#OpenPGP +my %hashes=( +"0"=>"", +"1"=>"-md md5", +"2"=>"-md sha1", +"3"=>"-md rmd160", +"8"=>"-md sha256", +"9"=>"-md sha384", +"10"=>"-md sha512"); +my %templates=( + "0"=>"client.cnf", + "1"=>"client-org.cnf", + "2"=>"client-codesign.cnf", + "3"=>"client-machine.cnf", + "4"=>"client-ads.cnf", + "5"=>"server.cnf", + "6"=>"server-org.cnf", + "7"=>"server-jabber.cnf", + "8"=>"ocsp.cnf", + "9"=>"timestamp.cnf", + "10"=>"proxy.cnf", + "11"=>"subca.cnf" +); + +my $starttime=5*60; # 5 minutes + +my %currenthash=(); + + +#End of configurations + +######################################################## + +mkdir "$work",0700; +mkdir "currentcrls"; + +$ENV{'PATH'}='/usr/bin/:/bin'; +$ENV{'IFS'}="\n"; +$ENV{'LD_PRELOAD'}=''; +$ENV{'LD_LIBRARY_PATH'}=''; +$ENV{'LANG'}=''; + +#Logging functions: +sub SysLog($) +{ + my $date=strftime("%Y-%m-%d",localtime); + open LOG,">>logfile$date.txt"; + return if(not defined($_[0])); + my $timestamp=strftime("%Y-%m-%d %H:%M:%S",localtime); + #$syslog->write($_[0]."\x00"); + print LOG "$timestamp $_[0]"; +# print "$timestamp $_[0]"; + flush LOG; + close LOG; +} + +sub Error($) +{ + SysLog($_[0]); + if($paranoid) + { + die $_[0]; + } +} + +sub readfile($) +{ + my $olds=$/; + open READIN,"<$_[0]"; + undef $/; + my $content=; + close READIN; + $/=$olds; + return $content; +} + + +#Hexdump function: Returns the hexdump representation of a string +sub hexdump($) +{ + return "" if(not defined($_[0])); + my $content=""; + $content.=sprintf("%02X ",unpack("C",substr($_[0],$_,1))) foreach (0 .. length($_[0])-1); + return $content; +} + +#pack3 packs together the length of the data in 3 bytes and the data itself, size limited to 16MB. In case the data is more than 16 MB, it is ignored, and a 0 Byte block is transferred +sub pack3 +{ + return "\x00\x00\x00" if(!defined($_[0])); + my $data=(length($_[0]) >= 2**24)? "":$_[0]; + my $len=pack("N",length($data)); + #print "len: ".length($data)."\n"; + return substr($len,1,3).$data; +} + + +#unpack3 unpacks packed data. +sub unpack3($) +{ + return undef if((not defined($_[0])) or length($_[0])<3); + #print "hexdump: ".hexdump("\x00".substr($_[0],0,3))."\n"; + my $len=unpack("N","\x00".substr($_[0],0,3)); + #print "len3: $len length(): ".length($_[0])." length()-3: ".(length($_[0])-3)."\n"; + return undef if(length($_[0])-3 != $len); + return substr($_[0],3); +} + + +#unpack3array extracts a whole array of concatented packed data. +sub unpack3array($) +{ + my @retarr=(); + if((not defined($_[0])) or length($_[0])<3) + { + SysLog "Datenanfang kaputt\n"; + return (); + } + my $dataleft=$_[0]; + while(length($dataleft)>=3) + { + #print "hexdump: ".hexdump("\x00".substr($dataleft,0,3))."\n"; + my $len=unpack("N","\x00".substr($dataleft,0,3)); + #print "len3: $len length(): ".length($dataleft)." length()-3: ".(length($dataleft)-3)."\n"; + if(length($dataleft)-3 < $len) + { + SysLog "Datensatz abgeschnitten\n"; + return (); + } + push @retarr, substr($dataleft,3,$len); + $dataleft=substr($dataleft,3+$len); + } + if(length($dataleft)!=0) + { + SysLog "Ende abgeschnitten\n"; + return (); + } + return @retarr; +} + + + + +my $timestamp=strftime("%Y-%m-%d %H:%M:%S",localtime); + +SysLog("Starting Server at $timestamp\n"); + +SysLog("Opening Serial interface:\n"); +#if(1) +#{ + +sub SerialSettings +{ + my $PortObj=$_[0]; + Error "Could not open Serial Port!\n" if(!defined($PortObj)); + $PortObj->baudrate(115200); + $PortObj->parity("none"); + $PortObj->databits(8); + $PortObj->stopbits(1); +} + +#We have to open the SerialPort and close it again, so that we can bind it to a Handle +my $PortObj = new Device::SerialPort($serialport); +SerialSettings($PortObj); +$PortObj->save("serialserver.conf"); +#} +undef $PortObj; + +$PortObj = tie (*SER, 'Device::SerialPort', "serialserver.conf") || Error "Can't tie using Configuration_File_Name: $!\n"; + +Error "Could not open Serial Interface!\n" if(not defined($PortObj)); +SerialSettings($PortObj); +#open SER,">$serialport"; + +SysLog("Serial interface opened: $PortObj\n"); + + +#Creating select() selector for improved reading: +my $sel = new IO::Select( \*SER ); + +#Raw send function over the Serial Interface (+debugging) +sub SendIt($) +{ + return unless defined($_[0]); + SysLog "Sending ".length($_[0])."\n"; #hexdump($_[0])."\n"; + my $data=$_[0]; + my $runcount=0; + my $total=0; + my $mtu=30; + while(length($data)) + { + my $iwrote=scalar($PortObj->write(substr($data,0,$mtu)))||0; + usleep(270*$iwrote+9000); # On Linux, we have to wait to make sure it is being sent, and we dont loose any data. + $total+=$iwrote; + $data=substr($data,$iwrote); + print "i wrote: $iwrote total: $total left: ".length($data)."\n" if(!($runcount++ %10)); + } + +# print "Sending ".length($_[0])."\n"; #hexdump($_[0])."\n"; +# foreach(0 .. length($_[0])) +# { +# $PortObj->write(substr($_[0],$_,1)); +# } + +} + + +#Send data over the Serial Interface with handshaking: +#Warning: This function is implemented paranoid. It exits the program in case something goes wrong. +sub SendHandshakedParanoid($) +{ + #print "Shaking hands ...\n"; + SendIt("\x02"); + + Error "Handshake uncompleted. Connection lost!" if(!scalar($sel->can_read(2))); + my $data=""; + usleep(1000000); + my $length=read SER,$data,1; + if($length && $data eq "\x10") + { + print "OK ...\n"; + my $xor=0; + foreach(0 .. length($_[0])-1) + { + #print "xor mit ".unpack("C",substr($_[0],$_,1))."\n"; + $xor ^= unpack("C",substr($_[0],$_,1)); + } + #print "XOR: $xor\n"; + + my $tryagain=1; + while($tryagain) + { + SendIt($_[0].pack("C",$xor)."rie4Ech7"); + + Error "Packet receipt was not confirmed in 5 seconds. Connection lost!" if(!scalar($sel->can_read(5))); + + $data=""; + $length=read SER,$data,1; + + if($length && $data eq "\x10") + { + SysLog "Sent successfully!...\n"; + $tryagain=0; + } + elsif($length && $data eq "\x11") + { + $tryagain=1; + } + else + { + Error "I cannot send! $length ".unpack("C",$data)."\n"; + } + } + + } + else + { + print "!Cannot send! $length $data\n"; + Error "!Stopped sending.\n"; + } +} + +sub Receive +{ + my $data=""; + my @ready = $sel->can_read(20); + + my $length=read SER,$data,1,0; + + #SysLog "Data: ".hexdump($data)."\n"; + + if($data eq "\x02") + { + my $modus=1; + SysLog "Start received, sending OK\n"; + SendIt("\x10"); + + my $block=""; + my $blockfinished=0; + my $tries=10000; + + while(!$blockfinished) + { + Error("Tried reading too often\n") if(($tries--)<=0); + + $data=""; + if(!scalar($sel->can_read(2))) + { + SysLog("Timeout!\n"); + return; + } + $length=read SER,$data,100,0; + if($length) + { + $block.=$data; + } + #SysLog("Received: $length ".length($block)."\n"); + $blockfinished=defined(unpack3(substr($block,0,-9)))?1:0; + + if(!$blockfinished and substr($block,-8,8) eq "rie4Ech7") + { + SysLog "BROKEN Block detected!"; + SendIt("\x11"); + $block=""; + $blockfinished=0; + $tries=10000; + } + + } + SysLog "Block done: \n";#.hexdump($block)."\n"; + SendIt("\x10"); + SysLog "Returning block\n"; + return($block); + } + else + { + Error("Error: No Answer received, Timeout.\n") if(length($data)==0); + Error("Error: Wrong Startbyte: ".hexdump($data)." !\n"); + } + + SysLog "Waiting on next request ...\n"; + +} + + +#Checks the CRC of a received block for validity +#Returns 1 upon successful check and 0 for a failure +sub CheckCRC($) +{ + my $block=$_[0]; + return 0 if(length($_[0])<1); + return 1 if($_[0] eq "\x00"); + my $xor=0; + foreach(0 .. length($block)-2) + { + #print "xor mit ".unpack("C",substr($block,$_,1))."\n"; + $xor ^= unpack("C",substr($block,$_,1)); + } + #print "XOR: $xor BCC: ".unpack("C",substr($block,-1,1))."\n"; + if($xor eq unpack("C",substr($block,-1,1))) + { + #print "Checksum correct\n"; + return 1; + } + else + { + #print "Checksum on received packet wrong!\n"; + return 0; + } + +} + +#Formatting and sending a Response packet +sub Response($$$$$$$) +{ + SendHandshakedParanoid(pack3(pack3(pack("C*",$_[0],$_[1],$_[2],$_[3])).pack3($_[4]).pack3($_[5]).pack3($_[6]))); +} + + +#Checks the parameters, whether the certificate system (OpenPGP, X.509, ...) is available, +#whether the specified root key is available, whether the config file is available, ... +#Returns 1 upon success, and dies upon error! +sub CheckSystem($$$$) +{ + my ($system,$root,$template,$hash)=@_; + if(not defined($templates{$template})) + { + Error "Template unknown!\n"; + } + if(not defined($hashes{$hash})) + { + Error "Hash algorithm unknown!\n"; + } + if(defined($rootkeys{$system})) + { + if($root<$rootkeys{$system}) + { + return 1; + } + else + { + Error "Identity System $system has only $rootkeys{$system} root keys, key $root does not exist.\n"; + } + } + else + { + Error "Identity System $system not supported"; + } + + return 0; +} + + +#Selects the specified config file for OpenSSL and makes sure that the specified config file exists +#Returns the full path to the config file +sub X509ConfigFile($$) +{ + my ($root,$template)=@_; + my $opensslcnf=""; + if($root==0) + { + $opensslcnf="/etc/ssl/openssl-$templates{$template}"; + } + elsif($root==1) + { + $opensslcnf="/etc/ssl/class3-$templates{$template}"; + } + elsif($root==2) + { + $opensslcnf="/etc/ssl/class3s-$templates{$template}"; + } + else + { + $opensslcnf="/etc/ssl/root$root/$templates{$template}"; + } + # Check that the config file exists + Error "Config file does not exist: $opensslcnf!" unless (-f $opensslcnf); + + return $opensslcnf; +} + +sub CreateWorkspace() +{ + mkdir "$work",0700; + my $id = (new File::CounterFile "./$work/.counter", "0")->inc; + mkdir "$work/".int($id/1000),0700; + mkdir "$work/".int($id/1000)."/".($id%1000),0700; + my $wid="$work/".int($id/1000)."/".($id%1000); + SysLog "Creating Working directory: $wid\n"; + return $wid; +} + + +sub SignX509($$$$$$$$) +{ + my ($root,$template,$hash,$days,$spkac,$request,$san,$subject)=@_; + + my $wid=CreateWorkspace(); + + my $opensslcnf=X509ConfigFile($root,$template); + + print "Subject: $subject\n"; + print "SAN: $san\n"; + + + $subject=~ s/\\x([A-F0-9]{2})/pack("C", hex($1))/egi; + $san=~ s/\\x([A-F0-9]{2})/pack("C", hex($1))/egi; + + Error "Invalid characters in SubjectAltName!\n" if($san=~m/[ \n\r\t\x00"'\\]/); + Error "Invalid characters in Subject: ".hexdump($subject)." - $subject\n" if($subject=~m/[\n\r\t\x00"'\\]/); + + print "Subject: $subject\n"; + print "SAN: $san\n"; + + my $extfile=""; + if($templates{$template}=~m/server/) #??? Should we really do that for all and only for server certs? + { + open OUT,">$wid/extfile"; + print OUT "basicConstraints = critical, CA:FALSE\n"; + print OUT "extendedKeyUsage = clientAuth, serverAuth, nsSGC, msSGC\n"; + print OUT "keyUsage = digitalSignature, keyEncipherment\n"; + print OUT "authorityInfoAccess = OCSP;URI:$OCSPUrl\n"; + print OUT "subjectAltName = $san\n" if(length($san)); + close OUT; + $extfile=" -extfile $wid/extfile "; + } + + my $cmd=($request=~m/SPKAC\s*=/)?"-spkac":"-subj '$subject' -in"; + + #my $cmd=$spkac?"-spkac":"-subj '$subject' -in"; + + + if(open OUT,">$wid/request.csr") + { + print OUT $request; + close OUT; + + my $do = `$opensslbin ca $hashes{$hash} -config $opensslcnf $cmd $wid/request.csr -out $wid/output.crt -days $days -key test -batch $extfile 2>&1`; + + SysLog $do; + + + if(open IN,"<$wid/output.crt") + { + undef $/; + my $content=; + close IN; + $/="\n"; + + $content=~s/^.*-----BEGIN/-----BEGIN/s; + SysLog "Antworte...\n"; + Response($ver,1,0,0,$content,"",""); + SysLog "Done.\n"; + if(!$debug) + { + unlink "$wid/output.crt"; + unlink "$wid/request.csr"; + unlink "$wid/extfile"; + } + } + else + { + Error("Could not read the resulting certificate.\n"); + } + } + else + { + Error("Could not save request.\n"); + } + unlink "$wid"; +} + +sub SignOpenPGP +{ + my ($root,$template,$hash,$days,$spkac,$request,$san,$subject)=@_; + + my $wid=CreateWorkspace(); + + if(! -f "secring$root.gpg") + { + Error "Root Key not found: secring$root.gpg !\n"; + } + + copy("secring$root.gpg","$wid/secring.gpg"); + copy("pubring$root.gpg","$wid/pubring.gpg"); + + my $keyid=undef; + + Error "Invalid characters in SubjectAltName!\n" if($san=~m/[ \n\r\t\x00"'\\]/); + Error "Invalid characters in Subject!\n" if($subject=~m/[ \n\r\t\x00"'\\;]/); + + + if(open OUT,">$wid/request.key") + { + print OUT $request; + close OUT; + + +#!!!! ?!? + #my $homedir=-w "/root/.gnupg" ? "/root/.gnupg":"$wid/"; + my $homedir="$wid/"; + + { + SysLog "Running GnuPG in $homedir...\n"; + my ($stdin,$stdout,$stderr) = (IO::Handle->new(),IO::Handle->new(),IO::Handle->new()); + + + SysLog "Importiere $gpgbin --no-tty --homedir $homedir --import $wid/request.key\n"; + + my $pid = open3($stdin,$stdout,$stderr, "$gpgbin --no-tty --homedir $homedir --command-fd 0 --status-fd 1 --logger-fd 2 --with-colons --import $wid/request.key"); + + if (!$pid) { + Error "Cannot fork GnuPG."; + } + $/="\n"; + while(<$stdout>) + { + SysLog "Received from GnuPG: $_\n"; + if(m/^\[GNUPG:\] GOT_IT/) + { + } + elsif(m/^\[GNUPG:\] GET_BOOL keyedit\.setpref\.okay/) + { + print $stdin "no\n"; + } + elsif(m/^\[GNUPG:\] ALREADY_SIGNED/) + { + } + elsif(m/^\[GNUPG:\] GOOD_PASSPHRASE/) + { + } + elsif(m/^\[GNUPG:\] KEYEXPIRED/) + { + } + elsif(m/^\[GNUPG:\] SIGEXPIRED/) + { + } + elsif(m/^\[GNUPG:\] IMPORT_OK/) + { + } + elsif(m/^\[GNUPG:\] IMPORT_RES/) + { + } + elsif(m/^\[GNUPG:\] IMPORTED ([0-9A-F]{16})/) + { + Error "More than one OpenPGP sent at once!" if(defined($keyid)); + $keyid=$1; + } + elsif(m/^\[GNUPG:\] NODATA/) + { + # To crash or not to crash, thats the question. + } + else + { + Error "ERROR: UNKNOWN $_\n"; + } + + } + + while(<$stderr>) + { + + SysLog "Received from GnuPG on stderr: $_\n"; + + if(m/^key ([0-9A-F]{8}): public key/) + { + #$keyid=$1; + } + } + + waitpid($pid,0); + + } + + Error "No KeyID found!" if(!defined($keyid)); + + + SysLog "Running GnuPG to Sign...\n"; + + { + my ($stdin,$stdout,$stderr) = (IO::Handle->new(),IO::Handle->new(),IO::Handle->new()); + + + + $ENV{'LANG'}=""; + + my $line="$gpgbin --no-tty --default-key $gpgID --homedir $homedir --default-cert-expire $days"."d --ask-cert-expire --cert-policy-url $CPSUrl --command-fd 0 --status-fd 1 --logger-fd 2 --sign-key $keyid "; + SysLog($line."\n"); + + my $pid = open3($stdin,$stdout,$stderr,$line); + + if (!$pid) { + Error "Cannot fork GnuPG."; + } + SysLog "Got PID $pid\n"; + while(<$stdout>) + { + SysLog "Received from GnuPG: $_\n"; + if(m/^\[GNUPG:\] GET_BOOL keyedit\.sign_all\.okay/) + { + print $stdin "yes\n"; + } + elsif(m/^\[GNUPG:\] GOT_IT/) + { + } + elsif(m/^\[GNUPG:\] GET_BOOL sign_uid\.okay/) + { + print $stdin "yes\n"; + } + elsif(m/^\[GNUPG:\] GET_BOOL sign_uid\.expire_okay/) + { + print $stdin "yes\n"; + } + elsif(m/^\[GNUPG:\] GET_LINE siggen\.valid\s?$/) + { + print $stdin "$days\n"; + } + elsif(m/^\[GNUPG:\] GET_LINE sign_uid\.expire\s?$/) + { + print "DETECTED: Do you want your signature to expire at the same time? (Y/n) -> yes\n"; + print $stdin "no\n"; + } + elsif(m/^\[GNUPG:\] GET_BOOL sign_uid\.replace_expired_okay/) + { + print $stdin "yes\n"; + } + elsif(m/^\[GNUPG:\] GET_BOOL sign_uid\.dupe_okay/) + { + print $stdin "yes\n"; + } + elsif(m/^\[GNUPG:\] GET_BOOL keyedit\.sign_revoked\.okay/) + { + print $stdin "no\n"; + } + elsif(m/^\[GNUPG:\] GET_BOOL sign_uid\.revoke_okay/) + { + print $stdin "no\n"; + } + elsif(m/^\[GNUPG:\] GET_BOOL sign_uid\.expired_okay/) + { + print "The key has already expired!!!\n"; + print $stdin "no\n"; + } + elsif(m/^\[GNUPG:\] GET_BOOL sign_uid\.nosig_okay/) + { + print $stdin "no\n"; + } + elsif(m/^\[GNUPG:\] GET_BOOL sign_uid\.v4_on_v3_okay/) + { + print $stdin "no\n"; + } + elsif(m/^\[GNUPG:\] GET_BOOL keyedit\.setpref\.okay/) + { + print $stdin "no\n"; + } + elsif(m/^\[GNUPG:\] ALREADY_SIGNED/) + { + } + elsif(m/^\[GNUPG:\] GOOD_PASSPHRASE/) + { + } + elsif(m/^\[GNUPG:\] KEYEXPIRED/) + { + } + elsif(m/^\[GNUPG:\] SIGEXPIRED/) + { + } + elsif(m/^\[GNUPG:\] NODATA/) + { + # To crash or not to crash, thats the question. + } + else + { + Error "ERROR: UNKNOWN $_\n"; + } + } + + while(<$stderr>) + { + + SysLog "Received from GnuPG on stderr: $_\n"; + + if(m/^key ([0-9A-F]{8}): public key/) + { + #$keyid=$1; + } + } + + + + waitpid($pid,0); + + } + +#$do = `( $extras echo "365"; echo "y"; echo "2"; echo "y")|$gpgbin --no-tty --default-key gpg@cacert.org --homedir $homedir --batch --command-fd 0 --status-fd 1 --cert-policy-url http://www.cacert.org/index.php?id=10 --ask-cert-expire --sign-key $row[email] 2>&1`; + + SysLog "Running GPG to export...\n"; + + my $do = `$gpgbin --no-tty --homedir $homedir --export --armor $keyid > $wid/result.key`; + SysLog $do; + $do = `$gpgbin --no-tty --homedir $homedir --batch --yes --delete-key $keyid 2>&1`; + SysLog $do; + + if(open IN,"<$wid/result.key") + { + undef $/; + my $content=; + close IN; + $/="\n"; + + $content=~s/^.*-----BEGIN/-----BEGIN/s; + SysLog "Antworte...\n"; + Response($ver,2,0,0,$content,"",""); + SysLog "Done.\n"; + + if(!$debug) + { + unlink "$wid/request.key"; + unlink "$wid/result.key"; + } + + } + else + { + SysLog "NO Resulting Key found!"; + } + } + else + { + Error "Kann Request nicht speichern!\n"; + } + + unlink("$wid/secring.gpg"); + unlink("$wid/pubring.gpg"); + unlink("$wid"); +} + +sub RevokeX509 +{ + my ($root,$template,$hash,$days,$spkac,$request,$san,$subject)=@_; + + Error "Invalid characters in SubjectAltName!\n" if($san=~m/[ \n\r\t\x00"'\\]/); + Error "Invalid characters in Hash!\n" if(! $subject=~m/^[0-9a-fA-F]+$/); + + SysLog "Widerrufe $PkiSystems{$_[0]}\n"; + SysLog "Aktueller Hash vom Webserver: $subject\n"; + + my $iscurrent=0; + + $currenthash{$root}=sha1_hex(readfile("revoke-root$root.crl")); + + print "Aktueller Hash vom Signingserver: $currenthash{$root}\n"; + + if($subject eq $currenthash{$root}) + { + print "Hash matches current CRL.\n"; + print "Deleting old CRLs...\n"; + foreach () + { + if($_ ne "currentcrls/$root/$subject.crl") + { + print "Deleting $_\n"; + unlink $_ ; + } + } + print "Done with deleting old CRLs.\n"; + $iscurrent=1; + } + + my $wid=CreateWorkspace(); + + my $opensslcnf=X509ConfigFile($root,$template); + + if(open OUT,">$wid/request.crt") + { + print OUT $request; + close OUT; + + my $do = `$opensslbin ca $hashes{$hash} -config $opensslcnf -key test -batch -revoke $wid/request.crt > /dev/null 2>&1`; + $do = `$opensslbin ca $hashes{$hash} -config $opensslcnf -key test -batch -gencrl -crldays 7 -crlexts crl_ext -out $wid/cacert-revoke.crl > /dev/null 2>&1`; + $do = `$opensslbin crl -inform PEM -in $wid/cacert-revoke.crl -outform DER -out $wid/revoke.crl > /dev/null 2>&1`; + unlink "$wid/cacert-revoke.crl"; + + if(open IN,"<$wid/revoke.crl") + { + undef $/; + my $content=; + close IN; + $/="\n"; + unlink "$wid/revoke.crl"; + + mkdir "currentcrls/$root"; + my $newcrlname="currentcrls/$root/".sha1_hex($content).".crl"; + open OUT,">$newcrlname"; + print OUT $content; + close OUT; + + if($iscurrent) + { + SysLog "Schicke aktuelles Delta...\n"; + system "xdelta delta revoke-root$root.crl $newcrlname delta$root.diff"; + Response($ver,2,0,0,readfile("delta$root.diff"),"",""); + #Response($ver,2,0,0,$content,"",""); + } + else + { + if(-f "currentcrls/$root/$subject.crl") + { + SysLog "Schicke altes Delta...\n"; + system "xdelta delta currentcrls/$root/$subject.crl $newcrlname delta$root.diff"; + + Response($ver,2,0,0,readfile("delta$root.diff"),"",""); + #Response($ver,2,0,0,$content,"",""); + } + else + { + SysLog "Out of Sync! Sending empty CRL...\n"; + Response($ver,2,0,0,"","",""); # CRL !!!!!!!!! + } + } + + open OUT,">revoke-root$root.crl"; + print OUT $content; + close OUT; + + + SysLog "Done.\n"; + } + } + unlink "$wid"; +} + + +sub analyze($) +{ + SysLog "Analysiere ...\n"; + #SysLog hexdump($_[0])."\n"; + + my @fields=unpack3array(substr($_[0],3,-9)); + Error "Wrong number of parameters: ".scalar(@fields)."\n" if(scalar(@fields)!=4); + + SysLog "Header: ".hexdump($fields[0])."\n"; + my @bytes=unpack("C*",$fields[0]); + + Error "Header too short!\n" if(length($fields[0])<3); + + Error "Version mismatch. Server does not support version $bytes[0], server only supports version $ver!\n" if($bytes[0]!=$ver); + + Error "Header has wrong length: ".length($fields[0])."!\n" if(length($fields[0])!=9); + + if($bytes[1] == 0) # NUL Request + { + SysLog "NUL Request detected.\n"; + if($fields[1]) + { + open OUT,">timesync.sh"; + print OUT "date -u $fields[1]\n"; + print OUT "hwclock --systohc\n"; + close OUT; + } + Response($ver,0,0,0,"","",""); + } + elsif($bytes[1]==1) # Sign Request + { + SysLog "SignRequest detected...\n"; + CheckSystem($bytes[2],$bytes[3],$bytes[4],$bytes[5]); + if($bytes[2]==1) + { + SignX509($bytes[3],$bytes[4],$bytes[5],($bytes[6]<<8)+$bytes[7], $bytes[8],$fields[1],$fields[2],$fields[3]); + } + elsif($bytes[2]==2) + { + SignOpenPGP($bytes[3],$bytes[4],$bytes[5],($bytes[6]<<8)+$bytes[7], $bytes[8],$fields[1],$fields[2],$fields[3]); + } + } + elsif($bytes[1]==2) # Revocation Request + { + SysLog "Revocation Request ...\n"; + CheckSystem($bytes[2],$bytes[3],$bytes[4],$bytes[5]); + if($bytes[2]==1) + { + RevokeX509($bytes[3],$bytes[4],$bytes[5],($bytes[6]<<8)+$bytes[7], $bytes[8],$fields[1],$fields[2],$fields[3]); + } + } + else + { + Error "Unknown command\n"; + } + +} + +SysLog "Server started. Waiting 5 minutes for contact from client ...\n"; + +#When started, we wait for 5 minutes for the client to connect: +my @ready=$sel->can_read($starttime); + + +my $count=0; + +#As soon as the client connected successfully, the client has to send a request faster than every 10 seconds +while(@ready = $sel->can_read(15) && -f "./server.pl-active") +{ + my $data=""; + #my $length=read SER,$data,1; + + #SysLog "Data: ".hexdump($data)."\n"; + + #Receive(); + + $data=Receive(); + SysLog "Analysing ...\n"; + analyze($data); + +# if($data eq "\x02") +# { +# #SysLog "Start empfangen, sende OK\n"; +# SendIt("\x10"); +# +# my $block=""; +# my $blockfinished=0; +# my $tries=10000; +# +# while(!$blockfinished) +# { +# Error "Tried reading too often\n" if(($tries--)<=0); +# +# $data=""; +# @ready = $sel->can_read(2); +# $length=read SER,$data,100; +# if($length) +# { +# $block.=$data; +# } +# $blockfinished=defined(unpack3(substr($block,0,-1)))?1:0; +# } +# #SysLog "Block done: ".hexdump($block)."\n"; +# if(CheckCRC($block)) +# { +# SendIt("\x10"); +# analyze($block); +# } +# else +# { +# Error "CRC Error\n"; +# } +# } +# else +# { +# Error "Error: Wrong Startbyte!\n"; +# } + + $count++; + + SysLog "$count requests processed. Waiting on next request ...\n"; + +} + + +Error "Timeout! No data from client anymore!\n"; +