P7m codificato

Grazie per l’eccellente sintesi di questo aspetto del protocollo. A questo punto ci metto poco a scrivere una routine per la pulizia. Che pubblico poi qui.
Ciao
Marco

Per la pulizia di una singola fattura conviene usare strumenti appositi tipo arubasign o dike e poi utilizzare xml estratto in un visualizzatore. Detti strumenti inoltre sono gli unici che consentono la verifica della firma digitale che se inutile nel caso di terzo soggetto o intermediario, potrebbe invece essere utile per verificare l’autenticità di fatture firmate direttamente dal prestatore.
Per flussi massivi invece credo che utilizzare openssl (disponibile anche su windows) sia sempre la soluzione migliore.

L’altro problema è identificare l’inizio e la fine del file xml all’interno del file p7m,
perché non tutti i file delle fatture elettroniche iniziano con <?xml. La dichiarazione xml è opzionale. Molti iniziano direttamente con l’elemento <FatturaElettronica>. Solo che può anche avere un prefisso per il namespace (<pippo:FatturaElettronica>).
A me questo approccio euristico non piace per niente, considerando che il formato è standard e documentato. La cosa migliore è utilizzare una libreria già pronta, oppure richiamare un programma esterno (tipo openssl).
Volendo usare una soluzione “fai-da-te”, andrebbe implementato il parsing dei file .p7m seguendo lo standard. Io ci ho messo un paio d’ore, basandomi su questa guida introduttiva al formato ASN.1:
http://luca.ntop.org/Teaching/Appunti/asn1.html

1 Mi Piace

Se vuoi puoi usare openssl_pkcs7_verify()
Devi passare come flags PKCS7_NOVERIFY per evitare failure in decodifica per mancanza della CA e PKCS7_BINARY se il file è in formato binary (eventualmente dopo averlo decodificato con base64_decode).
per scriverti un esempio:

openssl_pkcs7_verify ( "IT01234567890_00001.xml.p7m" , PKCS7_NOVERIFY|PKCS7_BINARY , "IT01234567890_00001.cert" , "" , "" , "IT01234567890_00001.xml");

puoi poi usare openssl_x509_read and openssl_x509_parse per analizzare il certificato se ti interessa.

Grazie della dritta. Farò una prova con il codice… Quello che avevo trovato mi dava sempre - 1

Il codice che ti ho dato sulle nuove versioni di PHP non funziona più almeno non con i setting di default.

per farlo funzionare (ed ottenere il file) ho dovuto fare delle porcate inenarrabili:

  1. ho dovuto ottenere una lista di CA…

  2. ho modificato la chiamata in questo modo

    openssl_pkcs7_verify ("IT01234567890_00001.xml.p7m-b6m" , 0 , null ,array("CA.pem"),"CA.pem","IT01234567890_00001.xml");

dove CA.pem è la lista delle possibili CA vedi questo sito per come ottenerne una

usa al posto di

https://applicazioni.cnipa.gov.it/TSL/_IT_TSL_signed.xml

https://eidas.agid.gov.it/TL/TSL-IT.xml

b6m è la versione SMIME del file p7m (leggi i post di openssl_pkcs7_verify per come creare quel file

per me è un UCAS…

ho visto tuttavia che esiste una libreria commerciale [Chilkat] che dovrebbe poter decodificare i file… https://www.example-code.com/phpext/crypt_extract_from_p7m.asp
Tuttavia:

  1. non l’ho mai provata e non garantisco
  2. non so se la puoi installare sui tuoi server

Ecco perchè a me piace avere la mia infrastruttura :slight_smile:

Grazie oggi provo a fare qualche test.
Si la libreria chilkat l’avevo trovata ma non mi è possibile installarla… oltre ad non essere free sfortunatamente.
Ora devo solo capire come convertire quello script .sh per recuperare i CA e convertirlo in funzione PHP e poi faccio qualche prova e vi tengo aggiornati. Uso ancora PHP 5.6 quindi spero di cavarmela con il primo codice postato.

anche nel caso di primo codice postato comunque il file deve essere in formato smime

Non so dove sbaglio ma non riesco a convertire il p7m come dici tu.
Mi restituisce solo un valore INT.

ho usato la funzione trovata:

function der2smime($file)
{
$to=<<<TXT
MIME-Version: 1.0
Content-Disposition: attachment; filename=“smime.p7m”
Content-Type: application/x-pkcs7-mime; smime-type=signed-data; name=“smime.p7m”
Content-Transfer-Encoding: base64
\n
TXT;
$from=file_get_contents($file);
$to.=chunk_split(base64_encode($from));
return file_put_contents($file,$to);
}

$file = “IT03461720173_00B60.xml.p7m”;
$smimefile = der2smime($file);
var_dump($smimefile); // restituisce solamente un INT

quella funzione converte il file in smime…
e ti ritorna 1 se ci riesce…

Ah ok non capivo perchè mi sovrascriveva l’originale.
Ad ogni modo non mi restituisce 1 ma credo la dimensione (nel mio caso mi da INT 9648)
Ad ogni modo ho modificato lo script per creare un secondo file su cui operare…ma ricevo errore:

Warning: openssl_pkcs7_verify(): error opening the file, CA.pem

Eppure il file CA.pem (che ho recuperato con il link allo script che mi hai indicato è presente. Il file CA.pem l’ho recuperato tramite virtualizzazione di ubuntu per fare prima e messo nella cartella dove faccio il test)

Funzione:

function der2smime($file)
{
$to=<<<TXT
MIME-Version: 1.0
Content-Disposition: attachment; filename=“smime.p7m”
Content-Type: application/x-pkcs7-mime; smime-type=signed-data; name=“smime.p7m”
Content-Transfer-Encoding: base64
\n
TXT;
$from=file_get_contents($file);

$to.=chunk_split(base64_encode($from));

return file_put_contents("smime.p7m-b6m",$to);

}

$file = “IT03461720173_00B60.xml.p7m”;

$response = der2smime($file);

var_dump($response);

$output = openssl_pkcs7_verify (“smime.p7m-b6m” , 0 , null ,array(“CA.pem”),“CA.pem”,“IT01234567890_00001.xml”);

var_dump($output); // <— sempre -1 con errore di cui sopra indicato

hai cambiato la url da cui prelevare i certificati CA come ti avevo scritto ?

si si ho messo la url che mi hai dato tu. per lo script sh che mi hai linkato ho visto che nel github erano presenti 2 versioni di script. io ho provato il primo che mi ha funzionato. dovevo usare il secondo? Comunque per sicurezza allego il CA.pem recuperato magari non è giusto? link a wetransfer: https://we.tl/t-VaCVN1AIOm

no il CA è giusto…
hai provato a verificare se quel P7M passa la verifica ufficiale della firma sul sito di infocamere ?
https://www.firma.infocert.it/utenti/verifica.php

Ciao in effetti ho mandato il mio file alla verifica e mi dice: File di input con formato non conosciuto

Eppure si tratta di una fattura passiva che ho ricevuto sul portale di aruba quindi è valida e ha passato i test dell’ AdE…

mi piacerebbe vedere quel file…
in 30 giorni ho visto molta fantasia fra i nostri colleghi programmatori…

inviato in pvt grazie

CVD:
da wikipedia (versione inglese)
The [UTF-8] representation of the BOM is the byte sequence 0xEF,0xBB,0xBF .
The Unicode Standard permits the BOM in [UTF-8] but does not require or recommend its use.

Ma qualche simpaticone li usa ugualmente…

Mi viene in mente di usare in successione queste regex:
\x04[\x00-\xF7]
\x04\x80.
\x04\x81…
\x04\x82…
Ecc

Ovviamete la terza è \x04\x81…