<%flags> inherit => '/init.comp' <%perl> my $BaseUrl = $r->dir_config('BaseUrl'); my $tmpDir = $r->dir_config('TmpDir')."/put_firmato-$$-".rand(999999); $Session{Put_firmato_tmpDir} = $tmpDir; mkdir $tmpDir || die "Errore creazione dir $tmpDir: $!\n"; my $field_file_firmato = $m->scomp('SELF:Field_filename'); my $file_firmato = $ARGS{$field_file_firmato}; use MIME::Base64; use MIME::Parser; use Archive::Zip; use Digest::SHA1; use File::Remove q(remove); use Date::Parse; my $dbh = $Session{Dbh}; #Firme da cercare nel file firmato my $Query_firme = $m->scomp('SELF:Query_firme'); my $sth_firme = $Query_firme ? $dbh->prepare($Query_firme) : undef; # Per verificare se nel DB e' presente la hash calcolata my $sth_archivio = $dbh->prepare($m->scomp('SELF:Query_archivio')); # Per aggiornare l'archivio caricando il file firmato my $sth_update_archivio = $dbh->prepare($m->scomp('SELF:Query_update_archivio')); sub fine(){ remove(\1, $Session{Put_firmato_tmpDir}); $m->out(q{
}); $m->abort(); exit; } # converte la stringa restituita dalla chiamata al metodo Java SubjectX500Principal->toString in un hash # in ingresso: CN=Nome Cognome, DNQ=2011121115933, SERIALNUMBER=IT:CODICEFISCALE, GIVENNAME=NOME, SURNAME=COGNOME, O=NON PRESENTE, C=IT sub SubjectX500stringToHash($){ my %Hash; for my $row (split(/, /, $_[0])){ my($key,$value) = split /=/, $row; $Hash{$key} = $value; } return \%Hash; } ############ ### MAIN ### ############ $Session{No_Compression}=1; ## disabilito la compressione del flusso per ottenere l'aggiornamento progressivo $m->autoflush; $m->out("

Upload File firmati

\n"); for(my $c=20;$c;$c--){ $m->out("\n"); } $m->flush_buffer; # elenco dei file da elaborare my @elenco_file; if($file_firmato !~ m/\.m7m$/i && $file_firmato !~ m/\.zip$/i && $file_firmato !~ m/\.tsd$/i) { $m->out("Il file trasmesso ($file_firmato) non ha estensioni .tsd, .m7m o .zip, contenenti i file pdf firmati e marcati temporalmente
\n"); fine(); } # Recupera il file temporaneo my $file_download = "$tmpDir/$file_firmato"; if($r->dir_config('MasonArgsMethod') eq 'CGI'){ my $query = $m->cgi_object(); my $fh = $query->param($field_file_firmato); if(!$fh){ my $err = $query->cgi_error; die $query->cgi_error if($err); die "Upload file failed!\n"; } link($query->tmpFileName($fh), $file_download) or die sprintf "link from '%s' failed: $!", $query->tmpFileName($fh); }else{ my $upload = $r->upload($field_file_firmato); $upload->link($file_download) or die sprintf "link from '%s' failed: $!", $upload->tempname; } if($file_firmato =~ m/\.zip$/i) { my $zip = Archive::Zip->new(); die "Il file non è in formato zip.

Error reading $file_download:$!" unless $zip->read($file_download) == 0; my @members = $zip->members(); my $memb; foreach $memb(@members) { my $filename = "$tmpDir/unzip_dir/".$memb->fileName(); if($filename !~ m/\/$/){ # scarto le cartelle $zip->extractMember($memb, $filename); push(@elenco_file, $filename); } } }else{ # inserisco nell'elenco direttamente il nome del file scaricato push(@elenco_file, $file_download); } # attivazione del servizio java per la verifica della firma use Inline ( Java => 'STUDY', SHARED_JVM => 1, START_JVM => 0, PORT => 7893, AUTOSTUDY => 1, # DEBUG => 2, DIRECTORY => $r->dir_config('VerifyService_directory'), STUDY => ['it.trento.comune.j4sign.verification.servlet.VerifyService'], CLASSPATH => $r->dir_config('VerifyService_classPath') ); # init classe nella Java Virtual Machine condivisa con i parametri di configurazione my $VerifyService = new HTML::Mason::Commands::it::trento::comune::j4sign::verification::servlet::VerifyService( $r->dir_config('VerifyService_confDir'), $r->dir_config('VerifyService_cnipaDir'), $r->dir_config('VerifyService_cnipaCa'), $r->dir_config('VerifyService_cnipaRoots'), $r->dir_config('VerifyService_fingerprintDigitPA') ); #Parser file MIME my $parser = new MIME::Parser; mkdir "$tmpDir/mime_dir" || die "Errore creazione dir $tmpDir/mime_dir: $!\n"; $parser->output_dir("$tmpDir/mime_dir"); # elaboro la lista dei file contenuti nel file compresso o il singolo file scaricato for my $sfile ( @elenco_file ) { my $filename = $sfile; $filename =~ s/^.*\///; $m->out("Check file $filename
\n"); $m->flush_buffer; my $fileP7M; my $timestampDate; # data di applicazione della marcatura temporale my $tsd; if($filename =~ m/\.m7m/i){ # il file è nel vecchio formato m7m (MIME) my $entity = $parser->parse_open($sfile); $fileP7M = $entity->parts(0)->{ME_Bodyhandle}->{MB_Path}; my $fileTSR = $entity->parts(1)->{ME_Bodyhandle}->{MB_Path}; if ($entity->parts != 2 || $fileP7M !~ m/\.p7m$/i || $fileTSR !~ m/\.tsr$/i) { $m->out("Era atteso un file in formato MIME contenente un file .p7m e un file con estensione .tsr ($filename)
"); fine(); } # data di applicazione della marcatura temporale (per la verifica della validità delle firme) my $token = $VerifyService->verifyTSR($fileTSR); # class org.bouncycastle.tsp.TimeStampToken # class org.bouncycastle.util.Store restituito chiamando token.getCertificates my $certificates = $token->getCertificates->getMatches(undef)->toArray; foreach my $cert (@$certificates){ # class $m->out('Timestamp emesso da: '.$cert->getIssuer->toString); } $timestampDate = $token->getTimeStampInfo->getGenTime; }elsif($filename =~ m/\.tsd/i){ # il file è nel formato p7m TSD? my $res = $VerifyService->parseTSD($sfile); $fileP7M = "$sfile.p7m"; if(!$VerifyService->validateTSD($fileP7M)){ # nome del file contenuto nella busta, da salvare $m->out("Il file $sfile non contiene un certificato .p7m marcato temporalmente (TSD).
\n"); fine(); } my $tokens = $VerifyService->tokensTSD; foreach my $token (@$tokens){ my $certificates = $token->getCertificates->getMatches(undef)->toArray; foreach my $cert (@$certificates){ $m->out('Timestamp emesso da: '.$cert->getIssuer->toString); } $timestampDate = $token->getTimeStampInfo->getGenTime; last; } $tsd = 1; }elsif($filename =~ m/\.p7m/i){ $m->out("Il formato P7M che contenesse firme marcate temporalmente nello standard CADES-T non è supportato; utilizzare la marcatura temporale nel formato TSD: il file $filename è stato scartato
\n"); next; }else{ $m->out("Formato sconosciuto: il file $filename è stato scartato
\n"); next; } # conversioni e test sulla data my $date_string = $timestampDate->toString; my $date_sec = str2time($date_string); my($sec,$min,$hour,$mday,$mon,$year) = localtime($date_sec); my $date_iso = sprintf('%04i-%02i-%02i %02i:%02i:%02i', 1900+$year, $mon+1, $mday, $hour, $min, $sec); $m->out(" il giorno: $date_iso
\n"); if(!$tsd){ # limite di validità della data per il formato M7M my $date_limit = $r->dir_config('VerifyService_validityMPMdate'); my $date_limit_sec = str2time($date_limit); if($date_sec >= $date_limit_sec){ $m->out("La data della marcatura temporale eccede il limite ($date_limit) concordato per il formato M7M
\n"); next; } } # verifica delle firme nel file firmato my $Risultati = $VerifyService->verifyP7M($fileP7M, $timestampDate); # salvataggio del file firmato $VerifyService->saveContent("$fileP7M.content"); # slurp file open SLURP, "<$fileP7M.content" || die "$! file $fileP7M.content\n"; my $let_file = do{local $/; }; close SLURP; # codifica del file nel formato base64 $let_file = encode_base64($let_file); # Calcola hash sul file letto my $hash = Digest::SHA1::sha1_hex($let_file, "password"); # Verifica se nel DB e' presente la hash calcolata $sth_archivio->execute($hash); my $file_sconosciuto = 1; while(my $archivio = $sth_archivio->fetchrow_hashref){ my $update_nuovo_file = 1; $file_sconosciuto = 0; if($archivio->{marca_temporale}){ $m->out("Un file firmato è già presente in archivio con il codice $archivio->{'codice'}
\n"); $update_nuovo_file = 0; }else{ my %lista_firme_verifica; if($sth_firme){ # verifico che i soggetti firmatari coincidano con i firmatari dichiarati in archivio utilizzando il Codice Fiscale $sth_firme->execute($hash, $hash, $hash, $hash); while(my $row = $sth_firme->fetchrow_hashref) { $lista_firme_verifica{uc $row->{codice_fiscale}} = $row; } } # lettura e confronto dei risultati foreach my $result (@{$Risultati->values->toArray}){ my $cert = $result->getCert; # class org.bouncycastle.jce.provider.X509CertificateObject my $X500str = $cert->getSubjectX500Principal->toString; # class javax.security.auth.x500.X500Principal my $Subject = SubjectX500stringToHash($X500str); $m->out("Firmato da: $X500str
\n"); if(!$result->isPassed){ $m->out("Test validità della firma fallito! ( range date ".$cert->getNotBefore->toString." - ".$cert->getNotAfter->toString.")
\n"); $update_nuovo_file = 0; next; } # confronto degli attributi dei soggetti firmatari my $CF; # Codice Fiscale if($Subject->{SERIALNUMBER}){ $CF = $Subject->{SERIALNUMBER}; $CF =~ s/^IT://; }elsif($Subject->{CN}){ my @fields = split /\//, $Subject->{CN}, 4; $CF = $fields[2]; } my $firma = $lista_firme_verifica{uc $CF}; if($firma){ # firmatario presente # verifico che nome e cognome corrispondano if(uc $Subject->{GIVENNAME} ne uc $firma->{'nome'} || uc $Subject->{SURNAME} ne uc $firma->{'cognome'}){ $m->out("Test nominativo non corrispondente: ( $Subject->{GIVENNAME} $Subject->{SURNAME} <> $firma->{'nome'} $firma->{'cognome'} )
\n"); $update_nuovo_file = 0; next; } # lo tolgo dalla lista per verificare poi le firme mancanti delete $lista_firme_verifica{uc $CF}; }else{ # firmatario non previsto: lo ignoro } } # verifica firme mancanti foreach my $CF (keys %lista_firme_verifica){ $update_nuovo_file = 0; my $sogg = $lista_firme_verifica{$CF}; $m->out("Manca la firma di $sogg->{nome} $sogg->{cognome} - C.F. $CF
\n"); } } if($update_nuovo_file){ # aggiorno l'archivio con il file firmato e marcato temporalmente open FIRMATO, "<$sfile" || die "$! file $sfile\n"; my $firmato = do{local $/; }; close FIRMATO; $sth_update_archivio->execute($tsd, encode_base64($firmato), $timestampDate->toString, $hash); $dbh->commit(); $file_sconosciuto = 0; $m->out("Verifica e archiviazione file firmato eseguita con successo ($filename)
"); } } if($file_sconosciuto){ $m->out("Hash del file: ".$hash."
"); $m->out("File pdf contenuto nel file firmato non presente nell'archivio ($filename)
\n"); } } $m->out("
"); fine();