#!/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::SHA 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 "keyUsage = critical, digitalSignature, keyEncipherment, keyAgreement\n"; print OUT "extendedKeyUsage = clientAuth, serverAuth, nsSGC, msSGC\n"; print OUT "authorityInfoAccess = OCSP;URI:$OCSPUrl\n"; my $CRLUrl=""; if($root==0) { $CRLUrl="http://crl.cacert.org/revoke.crl"; } elsif($root==1) { $CRLUrl="http://crl.cacert.org/class3-revoke.crl"; } elsif($root==2) { $CRLUrl="http://crl.cacert.org/class3s-revoke.crl"; } else { $CRLUrl="http://crl.cacert.org/root${root}.crl"; } print OUT "crlDistributionPoints = URI:${CRLUrl}\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] =~ /^\d+\.\d+$/) { 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";