Digital signatures and files with extension p7m
You will have to open a file with the p7m extension, that is, those coming from the PEC and signed digitally.
Well! It happened to me a few days ago.
Having no software running the file directly I lost some time to extract both the content and the signatures and verify the correctness.
So not to waste more time with you (but also with me when I recap) I think an article is needed.
What is p7m format?
The p7m file is a CAdES (CMS Advanced Electronic Signatures) digital signature file that is an extension of the Cryptographic Message Syntax (CMS) which is based on PKCS#7.
So the p7m file is nothing more than a container that encapsulates both the original (non-encrypted) document and the personal digital signature and the CA chain that issued the certificate.
Going for order in the p7m file we find:
– In the first bytes the header PKCS#7
– then comes our original document (not encrypted)
– the signature hash (which validates by law the content)
– the personal digital certificate of those who signed it
– the CA certificate
Let’s consider the case where the signed document is a pdf (document.pdf.p7m).
The easiest way to view pdf encapsulated in document.pdf.p7m is to open it directly with a pdf editor like acroread o okular o evince since the PKCS#7 header should be a few bytes so if we rename the pdf extension file almost definitely, standard readers will be able to view the file directly without having to extract the content (maybe with some error message during opening).
To do the most accurate things we can try to edit the .p7m file with “vim” and directly delete the first bytes (50-100) up to
Per far le cose più precise possiamo provare ad editare il file .p7m con “vim” ed eliminare direttamente i primi byte (50 – 100) sino a %PDF-1 (Naturally leaving the %PDF-1 string as the .pdf file startup).
Since we are, we try to extract it correctly by also deleting the later bytes in pdf, that is, the %%EOF string.
At this point, the pdf document will be extracted correctly.
To extract it with a single command, without editing it, we can use the command
perl -ne 's/^.*%PDF/%PDF/; print if /%PDF/../%%EOF/' document.pdf.p7m >document.pdf
or we use the openssl command with the smime parameter for signature verificationo (-verify)
openssl smime -verify -noverify -in document.pdf.p7m -inform DER -out document.pdf
Extract the certificate
To extract the personal digital certificate of those who signed it just use openssl with the command
openssl pkcs7 -inform DER -in document.pdf.p7m -print_certs -out cert.pem
The certificate is in the cert.pem file and if you want to display text just use the x509 certificate command
openssl x509 -in cert.pem -text -noout
Checking the signature of the entire document
To check the signature, you must use the command
openssl smime -in document.pdf.p7m -inform DER -verify -out document.pdf
while to verify the validity of the simple certificate the command is
openssl verify cert.pem
Of course, trying it as it is, verification fails (“unable to load certificate“) because we do not have CA trust certificates.
If you try to verify the signature of a p7m file without the Certification Authority (la CA), the verification fails (“unable to load certificate“) because we do not have CA trust certificates (so-called Trusts).
These Certificate Authorities have been defined by Italian law and are registered on the CNIPA, which since December 2009 has become DigitPA, as a certificate of XML certificates and found them on the same site at https://applicazioni.cnipa.gov.it/TSL/_IT_TSL_signed.xml.
To have openssl manage them you have to put them in its format so:
wget -O - https://applicazioni.cnipa.gov.it/TSL/IT_TSL_signed.xml | perl -ne 'if (/<X509Certificate>/) {
s/^\s+//; s/\s+$//;
s/<\/*X509Certificate>//g;
print "-----BEGIN CERTIFICATE-----\n";
while (length($_)>64) {
print substr($_,0,64)."\n";
$_=substr($_,64);
}
print $_."\n";
print "-----END CERTIFICATE-----\n";
}' >CA.pem
This way we have all the certificates in a single CA.pem file, unfortunately even those that may have expired. Even if it’s over, we may need to check out an old file so we can also serve the expiration.
For script updates, please visit https://github.com/eniocarboni/getTrustCAP7m
Now we can check the certificate with a positive result with:
openssl verify -CAfile CA.pem cert.pem
and the file p7m with the command:
openssl smime -in documento.pdf.p7m -inform DER -verify -CAfile CA.pem -out documento.pdf
Of course, this last command, as well as checking the validity of the signature, also extracts the original document.
External links
CAdES see
CMS see
PKCS#7 see
24 thoughts on “p7m digital signature: how to extract the content”
Bel articolo, mi chiedo se fosse possibile con openssl anche generare file p7m
Ciao Antonio,
direi che per creare un p7m dato il file pdf “documento.pdf” basta utilizzare il comando “smime”
Per l’ultima versione smime, spero anche compatibile con il CNIPA, credo che bisogna utilizzare “cms” al posto di “smime”:
Perché sia valido a livello legale dovresti controllare il file con qualche tool presente online e fare tutti i controlli possibili.
Io invece ho una cartella zeppa di file in formato .p7m ed ho notato che la ricerca di una stringa di testo di windows non funziona; c’è qualcuno che può suggerire una soluzione?
Ciao Andrea,
non so bene come funzioni in windows ma non credo che riesca ad indicizzare direttamente i documenti presenti in file .p7m.
Sotto Linux basta utilizzare un semplice script come questo:
Supponiamo di salvarlo nel file find_in_p7m.sh nella stessa cartella dove sono i .p7m e supponendo sempre che i .p7m contengano pdf (per gli xml o altro bastano poche modifiche).
Lanciamo il comando per rendere eseguibile lo script:
e poi supponiamo di dover cercare la stringa “fattura” basta lanciare il comando:
che restituisce sia i file .p7m trovati che il contenuto trovato.
Credo che con powershell dovresti riuscire a far la stessa cosa sotto windows magari scaricandoti pdftotext da http://www.foolabs.com/xpdf/download.html e naturalmente avendo a disposizione openssl (http://gnuwin32.sourceforge.net/packages/openssl.htm)
Buona sera, se volessi estrarre il contenuto pdf da un p7m in php come potrei fare? sul mio host il servizio exec di php non è abilitato e devo usare solo funzioni di php
Grazie
Ciao Fabio,
purtroppo credo che in php la libreria OpenSSL (http://php.net/manual/en/ref.openssl.php) non permetta di usare “smime” per estrarre documenti nel formato CAdES (ma forse mi sbaglio e qualcuno mi correggerà).
Potresti, comunque, provare ad estrarlo direttamente dal file .p7m come l’ho descritto nell’articolo ovvero aprendo il file, saltando tutti i caratteri sino a (ma escluso) %PDF-1 e poi predi tutto sino a %%EOF ed il resto lo tralasci.
Non dovrebbe esser un operazione difficile (direi poche righe di codice).
Grazie della risposta. Ho provato anche quello ma, soprattutto per i pdf/a, l’estrazione della stringa così come descritto non produce un pdf valido
Ciao Fabio,
è molto strano che per i pdf/a non funzioni dato che il pdf/a non è altro che un sottoinsieme del pdf dove vengono eliminate tutte le funzioni che non permettono l’archiviazione a lungo termine (ad esempio la crittografia con password del testo).
Se hai un .pdf.p7m non personale che è possibile visionare prova a postare qui il link per poterlo verificare.
come convertire un file p7m in xml ?
Ciao Domenico, non mi è chiaro cosa vorresti convertire in xml
Io ho provato a cancellare le righe che stanno prima di %PDF-1 e tutto ciò che sta dopo %%EOF ma il PDF che ottengo è vuoto. Ho provato anche a lanciare la riga di comando:
E ottengo comunque un PDF con una pagina sola e completamente bianca
Ciao Roberto,
Forse nel tuo pdf c’è un’altra stringa %%EOF, magari come commento. In tal caso prova con:
dove in tal caso considero che %%EOF deve stare ad inizio riga.
Inoltre se il file pdf ha delle “modifiche incrementali” (incremental update) o revisioni queste vengono messe in coda aggiungendo i vari pezzi e terminando con un ulteriore %%EOF (ad esempio se il pdf firmato viene modificato e poi rifirmato nelle modifiche).
In tal caso devi lasciare tutti i %%EOF esistenti sino all’ultimo ed il comando “perl” non funzionerà mentre “openssl” dovrebbe andar sempre bene.
Fammi sapere se sei in uno di questi casi e se sei riuscito a risolvere.
Ciao Enio,
grazie innanzitutto della risposta. No anche con quella stringa non riesco, ottengo lo stesso PDF vuoto.
Alla fine ho usato l’altro tuo suggerimento (openssl) ma ora volevo chiederti una cosa in più se la sai. Sarebbe possibile tramite Java far la stessa cosa usando (immagino) la libreria openssl? Ne sai qualcosa? In questa maniera potrei fare io un .jar al volo che funzionerebbe anche su Windows.
Grazie e ciao.
Credo che dovresti partire da https://www.bouncycastle.org.
Se il tuo doc.pdf.p7m non è un documento riservato potresti girarmelo così da far delle prove ulteriori.
Se vuoi me lo puoi mandare in privato (in tal caso ti scrivo una mail personale).
Caio Enio,
bellissimo articolo! Mi hai aiutato a risolvere diverse grane (e a non usare Windows…)
In questi giorni ho scoperto che mentre alla pubblica amministrazione piacciono molto i file .P7M, spesso all’estero usano firmare i documenti tenendo separati file e firma (che ho scoperto si possono ottenere senza l’opzione -nodetach, quindi generando una “clear signature”).
Sai se esiste un modo, usando OpenSSL, per fare una sorta di “merging” tra il file e la sua firma (che come standard ha estensione .P7B) ottenendo un file .P7M?
Complimenti ancora! Ciao.
No purtroppo non saprei.
Grazie molte per i complimenti
Ciao Enio,
di recentissimo mi sono imbattuto nei problemi di firma digitale… e quindi in questo “fantastico” meccanismo messo in piedi dalla nostra PA.
Sai dov’è possibile trovare la specifica del file P7M? Spero l’abbiano fatta open…
Poi mi frulla un’altra idea, fatto 30 facciamo 31: chiaro il meccanismo con cui leggo e produco il file P7M con openSSL… ma come recupero la mia chiave privata imprigionata nella smart card che mi hanno dato? Sai se openSSL possa interfacciarsi ai lettori, oppure se c’è qualche tool che possa interaggire?
Grazie mille e ottimo lavoro!
Albe
Da quello che ho capito io: usando il driver apposito per la tua smartcard si può estrarre il certificato (io ci sono riuscito) però poi non è possibile usare openssl per generare una CADES a meno di non usare una versione modificata con una patch che, al momento, non è stata accettata nel programma originale. I dettagli li trovi qui: http://www.blia.it/firmadigitale/index.php
Io vorrei conoscere una applicazione che mi apre in serie, ovvero mi estrae immediatamente con un solo right-click da piu file selezionati, il file non firmato.
Oltre al DIKE che ne apre uno solo ed uno alla volta, ognuno in una finestra separata, non esiste altro ?
Grazie
è possibile generalizzare gli scripts di estrazione in modo tale che agiscano in batch su più files?
perl -ne ‘s/^.*%PDF/%PDF/; print if /%PDF/../%%EOF/’ documento.pdf.p7m >documento.pdf
openssl smime -verify -noverify -in documento.pdf.p7m -inform DER -out documento.pdf
grazie per l’ottimo articolo
Grazie per i complimenti.
Per elaborare in batch diversi file .pdf.p7m basta metterli in una directory e lanciare da lì la seguente riga di codice bash:
grazie per la cortese risposta
anche io sono riuscito a mettere insieme qualcosa del genere (sintassi leggermente differente e meno compatta)
############
for file in *.p7m
do
filename=”${file##*/}”
filename_new=”${filename%.*}”
openssl smime -verify -noverify -in “$filename” -inform DER -out “$filename_new”
done
##########
I needed these infos – for a friend – to submit a PDF with signature (as p7m) for an italian authority.
These infos here ARE practically the one and only ones – which really work in an understandable way.
esp. cool is the p7m binary for Linux 🙂 – as I can verify with that in a semi-independent way, whether the generated p7m-file looks plausible or not. – excellent work!
Thank you so much for the compliments and I am very happy to have been of help with this article on p7m.