Skip to content

Latest commit

 

History

History
659 lines (543 loc) · 40 KB

File metadata and controls

659 lines (543 loc) · 40 KB

english version - versione inglese

Libreria PKCS#7 Extractor per Delphi / Free Pascal / Lazarus

Libreria PKCS#7 Extractor per Delphi / Free Pascal / Lazarus

Questo progetto è nato dalla necessità di estrarre semplicemente il contenuto dei file .P7M in alcune applicazioni Delphi.
Dal 1 gennaio 2019 gli sviluppatori italiani hanno dovuto affrontare il nuovo sistema di Fatturazione Elettronica, divenuto obbligatorio per Legge.
Le Fatture Elettroniche sono esenzialmente rappresentante in file XML che vengono firmate digitalmente utilizzando la modalità CAdES-BEM.
Gli sviluppatori che gestiscono fatture devono quindi generare questi file XML ed essere in grado di rileggerli, ma quando si tratta di una fattura firmata digitalmente inglobata in un file .P7M molti di loro hanno trovato la soluzione poco ortodossa di rimuovere l'envelope trovando il tag di apertura e di chiusura XML all'interno del file e copiando quella parte.
Abbiamo pensato che questo non potesse essere il modo professionale di gestire questa operazione, quindi abbiamo iniziato a studiare e siamo finiti a creare questo progetto.

Indice

File inclusi

Che cosa è e come funziona

Questa è la unit principale con cui gli sviluppatori dovranno confrontarsi, esporta alcune utili funzioni per gestire i messaggi PKCS#7.

Funzioni esportate

Ogni funzione esportata ha una sua storia così lunga che a raccontarla nessuno ci crederebbe. Siamo chiari, non è stato per nulla facile, ma da ora dovrebbe esserlo. Iniziamo con il descrivere le funzioni esportate per il wrapper delle funzioni di OpenSSL.

function Load: Boolean;

Richiamare la funzione Load per inizializzare il wrapper, questo causerà se necessario il caricamento della libreria. Se è stata precedentemente specificata una cartella valida utilizzando la procedure SetFolder, verrà tentato di caricare la libreria dalla cartella specificata.
Il valore ritornato indica se il caricamento e/o collegamento della libreria è avvenuto con successo ed implica che tutte le funzioni necessarie siano state tornare.
Chiamare questa funzione più volte non ha alcun effetto pratico a meno che non venga scaricata prima la libreria.

function Loaded: Boolean;

Ritorna se il wrapper è attualmente inizializzato correttamente.

procedure Unload;

La procedure Unload causa la deinizializzazione del wrapper ma, come detto prima, la libreria rimarrà residente in memoria.

procedure SetFolder(const S: String);

Richiamare SetFolder prima di Load per impostare una cartella specifica da cui caricare la libreria. Si notic che qualora la libreria fosse già stata caricata da questo wrapper o da qualsiasi altro componente o classe, le chiamate a questa procedura non avranno alcun effetto pratico.
Se viene specificata una cartella non valida o una cartella in cui non si trovi la libreria, verranno seguiti i normali percorsi utilizzati dal sistema operativo per il caricamento della libreria.
Non ha alcun effetto nel caso la libreria sia linkata staticamente nell'eseguibile.

function GetFolder: String;

La funzione GetFolder ritorna il percorso assoluto da cui la libreria è attualmente caricata in memoria oppure una stringa vuota se la libreria non è presente in memoria.
Questo potrebbe differire dalla cartella specificata utilizzando SetFolder qualora la cartella specificata non sia valida o non contenga la libreria o ancora qualora la libreria fosse già precedentemente caricata.

function GetVersion: String;

La funzione GetVersion ritorna semplicemente la stringa contenente la versione della libreria attualmente caricata in memoria o una stringa vuota qualora il wrapper non sia inizializzato.
La funzione corrispondente è stata introdotta in OpenSSL dalla versione 0.9.7, qyuindi questa funzione ritornerà una stringa vuota con versioni precedenti.

function GetErrorCode: Cardinal;

Ritorna un codice numerico che rappresenta l'ultimo errore interno della libreria OpenSSL.

function GetError(const ErrorCode: Cardinal): String;

Ritorna la descrizione testuale per un dato codice di errore.

function GetError: String;

Ritorna la descrizione testuale per l'ultimo errore interno della libreria OpenSSL.

Prima di continuare, è necessario prendere visione di due tipi indispensabili.

  TVerifyStatus = (vsUnknown, vsFull, vsPartial);
Valore Descrizione
vsUnknown Nessun dato è stato caricato o i dati non erano validi.
vsPartial I dati e la struttura dell'envelope sono stati verificati.
vsFull E' stata eseguita una verifica completa dei dati.
  TSignatureMode = (smUnknown, smPKCS7, smCMS);
Valore Descrizione
smUnknown Nessun dato è stato caricato o i dati non erano validi.
smPKCS7 I dati sono stati caricati ed erano imbustati con funzioni PKCS#7.
smCMS I dati sono stati caricati ed erano imbustati con funzioni CMS.

Quelle che seguono sono le funzioni di utilità.

function Extract(InStream, OutStream: TStream): Boolean;

Dato un messaggio PKCS#7 presente in uno stream, ritorna il contenuto estratto ad un altro stream.
Ritorna se l'operazione è andata a buon fine o meno.
Si prega di notare che InStream.Position deve essere impostata al punto di inizio del messaggio PKCS#7 prima di richiamare questa funzione, perché la stessa abbia successo. La proprietà Position sarà variata al termine dell'esecuzione di questa funzione, anche se la stessa non ha prodotto un risultato positivo.
I dati risultati - se ve ne sono - sono aggiunti in coda al contenuto corrente dello stream di output, è quindi necessario fornire uno stream vuoto prima di richiamare questa funzione per ottenere solamente il contenuto del messaggio estratto.

function Extract(InFilename, OutFilename: String): Boolean;

Funzione parallela che estrae i dati da un file PKCS#7 specificato con nome file ad un altro file. Ritorna se l'operazione è avvenuta correttamente o meno.

function Extract(Filename: String): Boolean;

Estrae il contenuto di un file contenente un messaggio PKCS#7 usando come file di output un nome di file calcolato automaticamente. Ritorna se l'operazione è avvenuta correttamente o meno. Si tenga conto che se il nome di file di destinazione non può essere calcolato, l'operazione fallirà.
Per vedere come il file viene calcolato si legga della funzione GuessFilename qui sotto.

function GuessFilename(Filename: String): String;

Prova a calcolare il nome di file di destinazione di un dato file originale, il che significa rimuovere l'estensione aggiunta (solitamente ".p7m") dal nome di file.
Per verificare che l'estensione sia stata aggiunta invece che sostituita, se nel file risultante non dovesse esserci un'altra estensione, la funzione fallità e ritornerà il nome del file originale.

function Verify(Stream: TStream): TVerifyStatus;

Funzione necessaria a verificare se un dato stream contiene o meno un messaggio PKCS#7 valido. Come per Extract(TStream, TStream) ci si ricordi che la proprietà Position dello stream di input deve essere impostato all'inizio del messaggio PKCS#7 prima di essere passato a questa funzione.
A differenza di Extract(TStream, TStream) comunque, questa funzione manterrà il valore della proprietà Position al suo valore corrente.

function Verify(Filename: String): TVerifyStatus;

Verifica semplicemente che un dato file contenga un messaggio PKCS#7 valido.

function Extract(Stream: TStream; var S: String): Boolean;

Funzione per ottenere il contenuto di un messaggio PKCS#7 estratto da uno stream direttamente in una stringa. Se l'operazione fallisse il valore tornato sarebbe False e sarà tornata uns stringa vuota.

function ExtractToString(Filename: String; var S: String): Boolean;

Funzione per ottenere il contenuto di un messaggio PKCS#7 estratto da un file direttamente in una stringa. Se l'operazione fallisse il valore tornato sarebbe False e sarà tornata uns stringa vuota.

function SignatureMode(Stream: TStream): TSignatureMode; overload;

Ritorna il tipo di funzioni crittografiche utilizzate per imbustare dei dati. Preserva il valore della proprietà Position dello stream.

function SignatureMode(const Filename: String): TSignatureMode; overload;

Ritorna il tipo di funzioni crittografiche utilizzate per imbustare un file.

Classi esportate

Quasta unit esporta una classe chiamata TPKCS7Message che è il cuore pulsante dove il lavoro viene svolto. Qualora si preferisse lavorare con questa, ecco come funziona. Si informa che a differenza delle suddette funzioni rapide, questa classe non tenta di caricare la libreria da sola, quindi bisogna sempre ricordare di richiamare Load() prima di utilizzarla.

constructor TPKCS7Message.Create;

Crea un'istanza della classe.

procedure TPKCS7Message.Clear;

Pulisce tutte le variabili locali cancellando eventuali dati caricati.

function TPKCS7Message.LoadFromStream(Stream: TStream): Boolean;

Carica un messaggio PKCS#7 da uno stream, ritorna True al successo.

function TPKCS7Message.LoadFromFile(Filename: String): Boolean;

Carica un messaggio PKCS#7 da un file, ritorna True al successo.

function TPKCS7Message.SaveToStream(Stream: TStream): Boolean;

Salva il contenuto precedentemente caricato con LoadFromStream o LoadFromFile su uno stream, ritorna True al successo.

function TPKCS7Message.SaveToFile(Filename: String): Boolean;

Salva il contenuto precedenemtente caricato con LoadFromStream o LoadFromFile su un file, ritorna True al successo.

property SignatureMode: TSignatureMode;

Proprietà in sola lettura che rappresenta il tipo di funzioni crittografiche utilizzate per imbustare i dati.

property VerifyStatus: TVerifyStatus;

Proprietà in sola lettura che rappresenta il tipo di verifica che è stata effettuata sui dati.

Evento OnStreamCreate

La classe estrae tutto il contenuto dai dati e li memorizza durante l'uso delle funzioni LoadFromStream o LoadFromFile. Si è scelto di memorizzare i dati in memoria RAM utilizzando un TMemoryStream, visto che i dati per cui era inizialmente destinata questa classe dovevano essere di dimensioni ridotte. Tuttavia è possibile che ci sia la necessità di reindirizzare i dati estratti altrove, per questo motivo è stato definito un evento, scatenato nel momento in cui la classe ha bisogno di allocare lo spazio dove memorizzare i dati. In questo modo è possibile redirigere i dati a qualsiasi discendente di TStream che sia scrivibile.

property OnStreamCreate: TStreamCreateEvent;

Per esempio potremo definire nella nostra Form un evento con cui andare a creare un file temporaneo.

type
  TMyForm = class(TForm)
    ...
    procedure FormCreate(Sender: TObject);
  private
    FPKCS7Message: TPKCS7Message;
  protected
    procedure PKCS7Stream(Sender: TObject; var AStream: TStream);
    ...

...
procedure TMyForm.PKCS7Stream(Sender: TObject; var AStream: TStream);
begin
  AStream := TFileStream.Create('temp.tmp', fmCreate or fmOpenReadWrite or fmShareDenyWrite)
end;

...

procedure TMyForm.FormCreate(Sender: TObject);
begin
  FPKCS7Message := TPKCS7Message.Create;
  FPKCS7Message.OnStreamCreate := PKCS7Stream;
...
end;
...

La classe si occuperà di richiamare il Free dello stream creato quando questo non sarà più necessario.

ADDENDUM: nella cartella "Utils" potete trovare il file CCLib.TempFileStream.pas che non fa parte di questa libreria ma è liberamente disponibile. Esporta una semplice classe discendente da TStream che crea un file temporaneo con nome casuale nella cartella temporanea di sistema, impedendone l'accesso ad altre applicazioni. Questo file sarà eliminato automaticamente quando verrà richiamato il metodo Free della classe.

Applicazione demo

L'applicazione demo contenuto nella cartella \Demo è un semplice estrattore che permette inoltre di cambiare la cartella da cui le librerie OpenSSL vengono caricate e selezionare un file, estrarlo verso un file di destinazione e visualizzare il suo contenuto in un controllo TMemo.

Schermata della applicazione demo

Unit tests

La unit tests contenuta nella cartella \Tests è un progetto di un'applicazione console che esegue tutta una serie di test sulla libreria e sul wrapper.

Il software richiede l'esistenza di alcune cartelle e file all'interno della stessa cartella in cui l'eseguibile viene lanciato, ecco una lista delle cartelle e che cosa devono contenere.

Nome cartella Obbligatoria? Descrizione
Data SI Questa cartella deve contenere una serie di file sui quali i test saranno eseguiti.
DataCheck SI In questa cartella devono essere contenuti dei file con i risultati attesi dall'estrazione dei file nella cartella "Data". Ogni file deve avere esattamente lo stesso nome file ed estensione del file sorgente. I test verranno eseguiti solamente sui file che hanno corrispondenza nelle due cartelle.
OpenSSL\x32 NO* Questa cartella deve contenere delle sottocartelle ognuna delle quali deve contenere le librerie di OpenSSL in forma binaria. I test verranno eseguiti per ogni cartella trovata. Inserire qui solamente librerie compilate a 32-bit
OpenSSL\x64 NO* Stessa cosa di cui sopra, ma per le librerie 64-bit.
Temp NO** Questa cartella è utilizzata mentre i test vengono eseguiti per salvare alcuni file. Non inserire alcun file in questa cartella, questa cartella verrà eliminata ogni volta che vengono eseguiti i test.

Addendum
* Questa cartella è richiesta solamente se l'applicazione demo è compilata per questa architettura.
** Questa cartella verrà creata automaticamente dal software ogni volta che viene eseguito.

Salvare un report dei test

Per salvare un report dei test su un file di testo per una migliore analisi - o per smettere di perder tempo a scorrere la console - torna utile la redirezione dell'output.

 PKCS7ExtractorTest.exe >report.txt

Genererà un file chiamato "report.txt" contenente tutte le informazioni necessarie.

Ottenere una lista delle librerie OpenSSL

Per ottenere una lista delle librerie OpenSSL presenti nelle cartelle .\OpenSSL\x32 e/o .\OpenSSL\x64 è possibile eseguire il programma di testo come:

 PKCS7ExtractorTest.exe /list

Questo causerà l'output delle sole versioni delle librerie che il programma è in grado di caricare. Per salvare questa lista su un file di testo, è possibile sfruttare la ridirezione dell'output eseguendo il comando:

 PKCS7ExtractorTest.exe /list >output.txt

Questo genererà un file chiamato "output.txt".

Eseguire i test solo su alcune versioni di OpenSSL

Avendo una lunga lista di versioni diverse di OpenSSL nella cartella .\OpenSSL perdavamo molto tempo eseguendo i test, per questa ragione abbiamo implementato la possibilità di specificare quali versioni eseguire.
E' sufficiente eseguire l'eseguibile specificando i nomi delle sottocartelle da cui caricare, ad esempio:

 PKCS7ExtractorTest.exe 0.9.6 openssl-0.9.8x-i386-win32 "openssl ultima"

Eseguirà i test solamente con le librerie presenti nella cartelle chiamate "0.9.6", "openssl-0.9.8x-i386-win32" e "openssl ultima".

File necessari

Il progetto richiede le librerie GNU Win32/64 binarie per Windows.
La versione minima supportata dovrebbe essere la 0.9.6 rilasciata il 24 settembre 2000. Non siamo in grado di testare librerie precedenti a tale versione.
Con la versione 1.1.0 le librerie OpenSSL hanno avuto una riscrittura importante e stiamo attualmente lavorando per capire come rendere questa librerie compatibile con entrambe le versioni. Non garantiamo che questa libreria sarà in futuro compatibile con tali versioni.

Questa unit è stata testata con le seguenti versioni binarie:

Versione Data x86 x64 Note
0.9.6 24 Sep 2000 N/A
0.9.6b 9 Jul 2001 N/A
0.9.6i ??? ??? ??? siamo alla ricerca di questa versione
0.9.6j ??? ??? ??? siamo alla ricerca di questa versione
0.9.6k 30 Sep 2003 NO N/A STIAMO ATTUALMENTE INVESTIGANDO SU QUESTO PROBLEMA
0.9.6l ??? ??? ??? siamo alla ricerca di questa versione
0.9.6m 17 Mar 2004 NO N/A STIAMO ATTUALMENTE INVESTIGANDO SU QUESTO PROBLEMA
0.9.7 ??? ??? ??? siamo alla ricerca di questa versione
0.9.7a ??? ??? ??? siamo alla ricerca di questa versione
0.9.7b ??? ??? ??? siamo alla ricerca di questa versione
0.9.7c ??? ??? ??? siamo alla ricerca di questa versione
0.9.7d ??? ??? ??? siamo alla ricerca di questa versione
0.9.7e ??? ??? ??? siamo alla ricerca di questa versione
0.9.7f ??? ??? ??? siamo alla ricerca di questa versione
0.9.7g ??? ??? ??? siamo alla ricerca di questa versione
0.9.7h ??? ??? ??? siamo alla ricerca di questa versione
0.9.7i ??? ??? ??? siamo alla ricerca di questa versione
0.9.7j 04 May 2006 NO N/A STIAMO ATTUALMENTE INVESTIGANDO SU QUESTO PROBLEMA
0.9.7k ??? ??? ??? siamo alla ricerca di questa versione
0.9.7l ??? ??? ??? siamo alla ricerca di questa versione
0.9.7m 23 Feb 2007 NO N/A STIAMO ATTUALMENTE INVESTIGANDO SU QUESTO PROBLEMA
0.9.8 ??? ??? ??? siamo alla ricerca di questa versione
0.9.8a ??? ??? ??? siamo alla ricerca di questa versione
0.9.8b ??? ??? ??? siamo alla ricerca di questa versione
0.9.8c ??? ??? ??? siamo alla ricerca di questa versione
0.9.8d ??? ??? ??? siamo alla ricerca di questa versione
0.9.8e 23 Feb 2007 N/A
0.9.8f ??? ??? ??? siamo alla ricerca di questa versione
0.9.8g ??? ??? ??? siamo alla ricerca di questa versione
0.9.8h 28 May 2008
0.9.8h 28 May 2008 N/A Indy / IntraWeb Edition
0.9.8i 15 Sep 2008
0.9.8j 07 Jan 2009
0.9.8k 25 Mar 2009
0.9.8l 5 Nov 2009
0.9.8l 5 Nov 2009 N/A Indy Backport
0.9.8m 25 Feb 2010
0.9.8n ??? ??? ??? siamo alla ricerca di questa versione
0.9.8o 01 Jun 2010
0.9.8p ??? ??? ??? siamo alla ricerca di questa versione
0.9.8q 2 Dec 2010
0.9.8r 8 Feb 2011
0.9.8r 8 Feb 2011 rev.2
0.9.8s 4 Jan 2012
0.9.8t 18 Jan 2012
0.9.8u 12 Mar 2012
0.9.8v ??? ??? ??? siamo alla ricerca di questa versione
0.9.8w 23 Apr 2012
0.9.8x 10 May 2012
0.9.8y 5 Feb 2013
0.9.8za ??? ??? ??? siamo alla ricerca di questa versione
0.9.8zb 6 Aug 2014
0.9.8zc 15 Oct 2014
0.9.8zd 8 Jan 2015
0.9.8ze 15 Jan 2015
0.9.8zf 19 Mar 2015
0.9.8zg 11 Jun 2015
0.9.8zh 3 Dec 2015
1.0.0 29 Mar 2010
1.0.0a 1 Jun 2010
1.0.0b ??? ??? ??? searching fo this
1.0.0c 2 Dec 2010
1.0.0d 8 Feb 2011
1.0.0d 8 Feb 2011 rev.2
1.0.0e 6 Sep 2011
1.0.0f 4 Jan 2012
1.0.0g 18 Jan 2012
1.0.0h 12 Mar 2012
1.0.0i 19 Apr 2012
1.0.0j 10 May 2012
1.0.0k 5 Feb 2013
1.0.0l 6 Jan 2014
1.0.0m ??? ??? ??? siamo alla ricerca di questa versione
1.0.0n 6 Aug 2014
1.0.0o 15 Oct 2014
1.0.0p 8 Jan 2015
1.0.0q 15 Jan 2015
1.0.0r 19 Mar 2015
1.0.0s 11 Jun 2015
1.0.0t 3 Dec 2015
1.0.1 14 Mar 2012
1.0.1a ??? ??? ??? siamo alla ricerca di questa versione
1.0.1b 26 Apr 2012
1.0.1c 10 May 2012
1.0.1d ??? ??? ??? siamo alla ricerca di questa versione
1.0.1e 11 Feb 2013
1.0.1f 6 Jan 2014
1.0.1g 7 Apr 2014
1.0.1h 5 Jun 2014
1.0.1i 6 Aug 2014
1.0.1j 15 Oct 2014
1.0.1k 8 Jan 2015
1.0.1l 15 Jan 2015
1.0.1m 19 Mar 2015
1.0.1o 12 Jun 2015
1.0.1p 9 Jul 2015
1.0.1q 3 Dec 2015
1.0.1r 28 Jan 2016
1.0.1s 1 Mar 2016
1.0.1t 3 May 2016
1.0.1u 22 Sep 2016
1.0.2 22 Jan 2015
1.0.2a 19 Mar 2015
1.0.2b ??? ??? ??? siamo alla ricerca di questa versione
1.0.2c 12 Jun 2015
1.0.2d 9 Jul 2015
1.0.2e 3 Dec 2015
1.0.2f 28 Jan 2016
1.0.2g 1 Mar 2016
1.0.2h 3 May 2016
1.0.2i 22 Sep 2016
1.0.2j 26 Sep 2016
1.0.2k 26 Jan 2017
1.0.2l 25 May 2017
1.0.2m 2 Nov 2017
1.0.2n 7 Dec 2017
1.0.2o 27 Mar 2018
1.0.2p 14 Aug 2018
1.0.2q 20 Nov 2018
1.0.2r 26 Feb 2019
1.0.2s 28 May 2019
1.0.2t 10 Sep 2019
1.0.2u 20 Dec 2019

La maggior parte di queste versioni binarie è stata trovata su indy.fulgan.com.
Siamo attualmente alla ricerca delle versioni binarie che ci mancano quindi fateci sapere qualora doveste trovarne qualcosa, saremo ben lieti di aggiungerle ai nostri test.
Ogni informazioni riguardante problemi di compatibilità sarà benvenuto. Si è deciso di ignorare le versioni 1.1.0+ da questa tabella, così come le versioni beta che non sono adatte alla distribuzione.

Nota sui file codificati Base64

La libreria non gestisce i file codificati Base64, leggere il presente capitolo per scoprire come abilitarne la gestione.

Da quando questa libreria è stata rilasciata, siamo spesso stati contattati da persone che utilizzandola hanno trovato dei file che non venivano correttamente gestiti e spesso ci venivano indicati come corrotti o "strani". Ad una attenta analisi tutti questi file erano semplicemente codificati attraverso l'algoritmo Base64 e vista la disponibilità di un gran numero di librerie, componenti o semplici unit che gestiscono tale formato, abbiamo sempre indirizzato altrove per porre rimedio.
La scelta di tale modus operandi è stata fatta anche sulla base dei risultati di un sondaggio sulle pagine del Delphi Club Italia nel quale infatti è emerso che tale funzionalità avrebbe dovuto esulare da questa libreria in quanto non parte del processo. Molti hanno evidenziato come tanti sviluppatori avessero già risolto in proprio la problematica con una propria implementazione di un decoder Base64.

Tuttavia recenti sviluppi ci hanno spinti nella direzione di integrare un controllo ed una gestione di tali file, anche in virtù del fatto che le librerie OpenSSL includono le funzionalità per la decodifica di tale formato, ma non applicano un riconoscimento automatico del formato in entrata delle funzioni.

Le funzioni delle librerie si aspettano infatti che i dati siano racchiusi tra due separatori di blocco come qui mostrato per indicare come interpretare il dato.

-----BEGIN PKCS7-----
Q2kgZmEgcGlhY2VyZSBjaGUgc2lhdGUgY3VyaW9zaSBkaSBjb25vc2NlcmUgaWwgY29udGVudXRv
IGRlbCBub3N0cm8gdGVzdG8gZGkgcHJvdmEsIG5vbiDDqCB1biBzZW1wbGljZSBsb3JlbSBpbXBz
dW0sIG1hIHVuIHRlc3QgYWQgaG9jLiBWaSBhdWd1cmlhbW8gdW5hIGJ1b25hIGdpb3JuYXRhLg==
-----END PKCS7-----

Per questo motivo, si è introdotta una funzione in apertura dei file che verifica se è in formato Base64 ed in tal caso aggiunge i tag di apertura e chiusura di blocco.

Nonostante le librerie OpenSSL non supportino la variante URL safe dell'alfabeto di Base64, tale procedura effettua il riconoscimento di entrambi gli alfabeti e eventualmente effettua conversione verso l'alfabeto standard.
Ciò introduce un possibile comportamento fallace in quanto un file nel quale vi sia la presenza mista di elementi distintivi dei due alfabeti non dovrebbe essere considerato un file codificato Base64 valido. Tuttavia si è valutato e si ritiene che l'evenienza che un file binario rientri in questa casistica sia talmente remota da non introdurre alcun tipo di problematica nell'utilizzo di questa libreria.

Questa modifica non ha alcun effetto su tutti i file che già precedentemente si aprivano tenendo conto che:

  • qualsiasi file binario contenga valori al di fuori dei suddetti alfabeti di Base64 - ad eccezione dei caratteri CR e LF - non viene modificato;
  • qualsiasi file codificato Base64 contenga già tali tag ricade già nella suddetta regola.

Chi volesse abilitare questa novità introdotta può semplicemente definire la direttiva di compilazione

{$DEFINE PKCS7MANAGEBASE64}

Presente anche in testa al file PKCS7Extractor.pas.

Cronologia versioni

  • Versione 1.3.0.0 rilasciata il 15 giugno 2021

    • aggiunta la gestione dei file codificati Base64 sfruttando un funzionamento interno delle librerie OpenSSL
      Tale funzionalità non è attivata di default, ma può esserlo definendo la direttiva di compilazione PKCS7MANAGEBASE64
  • Versione 1.2.0.0 rilasciata il 2 marzo 2020

    • aggiunta la gestione dei file firmati utilizzando le funzioni di crittografia CMS (richiede librerie OpenSSL 0.9.8h o successive)
    • ora compatibile con Lazarus / Free Pascal
    • il sorgente non è compatibile con compilatori precedenti a Delphi 6
    • tutta l'elaborazione è stata sposta in LoadFromStream, utilizza meno variabili di classe
    • TPKCS7Message.Verify è stata sostituita dalla proprietà TPKCS7Message.VerifyStatus
    • nuova proprietà TPKCS7Message.SignatureMode
    • nuove funzioni veloci SignatureMode(Stream) and SignatureMode(String)
    • nuovo evento TPKCS7Message.OnStreamCreate che consente di modificare la classe TStream da utilizzare
    • Extract(Stream, S) e ExtractToString ora gestiscono i BOM e le codifiche (Delphi 2009+)
    • aggiunte le funzioni GetErrorCode, GetError(Cardinal) e GetError
    • non è più necessario specificare le opzioni di verifica
    • non lascia un file vuoto quando si crea un nuovo file con SaveToFile e fallisce
    • spostate tutte le noiose definizioni delle strutture nell'implementation
    • evitato hint del compilatore Delphi (ne persistono alcuni molto sciocchi su Free Pascal / Lazarus)
    • aggiunto il file CCLib.TempFileStream.pas
    • testato con le librerie OpenSSL versioni 1.0.2q, 1.0.2r, 1.0.2s, 1.0.2t e 1.0.2u
    • risolti bug minori e riscritto parte di codice, rimosso lo zucchero sintattico
    • aggiunto file batch per la creazione automatica dei risultati attesi dei test
    • aggiornati README.md, LEGGIMI.md e lo screenshot della demo
    • ripristinato file dell'icona DCI nella cartella della demo
  • Versione 1.0.0.0 rilasciata il 27 novembre 2018

    • primo rilascio pubblico
    • correzione di errori minori
    • pulizia del codice ed aggiunta commenti
    • provato con alcune versioni in più di OpenSSL
  • Versione 0.9.5.0 - 26 novembre 2018

    • correzione errori
  • Versione 0.9.3.0 - 25 novembre 2018

    • la verifica supporta ora la verifica della firma
    • aggiunto il parametro per la verifica ad ogni funzione
  • Versione 0.9.0.0 - 25 novembre 2018

    • completamente modificata la struttura della libreria
    • ora è necessario un solo file
    • eliminate le due classi statiche Libeay32Wrapper e PKCS7Message
    • introdotta una classe TPKCS7Message, le funzioni rapide usano tale classe
  • Versione 0.8.2.0 - 24 novembre 2018

    • rimossa PKCS7LibraryLocation da PKCS7Extractor.pas utilizzare Libeay32Wrapper.GetLibraryFolder
    • rimossa PKCS7LibraryVersion da PKCS7Extractor.pas utilizzare Libeay32Wrapper.SSLeay_version
  • Versione 0.8.0.0 - 24 novembre 2018

    • aggiunta compatibilità x64
  • Versione 0.7.0.0 - 23 novembre 2018

    • rimossa la funzione Loaded da Libeay32Wrapper, utilizzare Load
    • riscritta completamente la funzione Load in Libeay32Wrapper
    • aggiunta funzione GetLibraryFolder per avere la posizione della libreria caricata
    • SSLeay_version non è più una semplice replica della funzione omonima esportata da OpenSSL ma una funzione più utile che ritorna una stringa contenente la versione
  • Versione 0.5.0.0 - 23 novembre 2018

    • abbandonata la dipendenza dal progetto Indy, utilizza ora un proprio wrapper minimale
    • rimossa la funzione PKCS7Check da PKCS7Extractor.pas utilizzare le funzioni Libeay32Wrapper.Load e .Loaded
    • aggiunto il file Libeay32Wrapper.pas
  • Versione 0.2.1.0 - 22 novembre 2018

    • aggiunta la funzione PKCS7GuessFilename
    • la funzione PKCS7Extract(Filename) ritorna ora il nome di destinazione o una stringa vuota
    • compatibile con Delphi 2007
  • Versione 0.2.0.0 - 22 novembre 2018

    • aggiunto PKCS7ExtractorTest.dpr
    • aggiunta la funzione PKCS7Check
    • aggiunta la funzione PKCS7LibraryLocation
    • aggiunta la funzione PKCS7LibraryVersion
    • aggiunta la funzione IsPKCS7
  • Versione 0.1.1.0 - 21 novembre 2018

    • risolta mancante inizializzazione della Libeay32.dll
  • Versione 0.1.0.0 - 20 novembre 2018

    • prima versione funzionante

Compatibilità con i compilatori

Vorremmo essere in grado di raggiungere la piena compatiblità con ogni compilatore Delphi (magari anche con Free Pascal), ma abbiamo bisogno che altri ci aiutino a testare il codice con compilatori di cui non abbiamo la licenza. Per ogni compilatore non indicato come compatibile stiamo aspettando che qualcuno si metta in contatto con noi per inviarci i test compilati con quel compilatore.

Compilatore S.O. Architettura Versione Tester/Note
Borland Delphi 1 🗻 N/A No 32-bit support.
Borland Delphi 2 🗻 x86 1.2.0.0 Christian Cristofori
Borland Delphi 3 🗻 x86 1.2.0.0 Non dovrebbe funzionare.
Borland Delphi 4 🗻 x86 1.2.0.0 Non dovrebbe funzionare.
Borland Delphi 5 🗻 x86 1.2.0.0 Non dovrebbe funzionare.
Borland Delphi 6 🗻 x86
Borland Delphi 7 🗻 x86 1.2.0.0 Marcello Gribaudo
💭 Borland Delphi 2005 🗻 x86
💭 Borland Delphi 2006 🗻 x86
💭 Turbo Delphi 2006 🗻 x86
CodeGear Delphi 2007 🗻 x86 1.2.0.0 Christian Cristofori
💭 Embarcadero Delphi 2009 🗻 x86
💭 Embarcadero Delphi 2010 🗻 x86
💭 Embarcadero Delphi XE 🗻 x86
💭 Embarcadero Delphi XE2 🗻 x86
💭 🗻 x64
💭 Embarcadero Delphi XE3 🗻 x86
💭 🗻 x64
💭 Embarcadero Delphi XE4 🗻 x86
💭 🗻 x64
💭 Embarcadero Delphi XE5 🗻 x86
💭 🗻 x64
💭 Embarcadero Delphi XE6 🗻 x86
💭 🗻 x64
Embarcadero Delphi XE7 🗻 x86 1.2.0.0 Diego Rigoni
🗻 x64 1.0.0.0 Diego Rigoni
💭 Embarcadero Delphi XE8 🗻 x86
💭 🗻 x64
💭 Embarcadero Delphi 10 Seattle 🗻 x86
💭 🗻 x64
Embarcadero Delphi 10.1 Berlin 🗻 x86 1.2.0.0 Gianni Giorgetti
🗻 x64 1.0.0.0 Christian Cristofori
Embarcadero Delphi 10.2 Tokyo 🗻 x86 1.0.0.0 Christian Cristofori
🗻 x64 1.0.0.0 Christian Cristofori
Embarcadero Delphi 10.3 Rio 🗻 x86 1.2.0.0 Christian Cristofori
🗻 x64 1.2.0.0 Christian Cristofori
Lazarus 2.0.6 Free Pascal 3.0.4 🗻 x86 1.2.0.0 Christian Cristofori
💭 🗻 x64
🐧 x86 *1.1.0.0 Christian Cristofori
💭 🐧 x64

*: la versione 1.1.0.0 non è mai stata più che una banale versione alpha.

Progetti per il futuro

La libreria è nata per un obiettivo che al momento pare essere stato ampiamente raggiunto.
Vista la longevità delle versioni crediamo che a questo punto la libreria si possa definire stabile e completa.
Non verranno pertanto aggiunte altre funzionalità, verranno pubblicate eventuali sotto-versioni per le seguenti motivazioni:

  • Correzioni e miglioramenti.
  • Rendere questa unit compatibile con ogni versione di Delphi o compilatore Object Pascal.
  • Compatibilità con ogni possibile versione di OpenSSL.

Ringraziamenti

Progetti che utilizzano questa libreria.

Questa libreria è utilizzabile liberamente dove e come si desidera, senza alcun obbligo. Ci farebbe però piacere avere un vostro feedback e aggiungere a questa lista un collegamento al vostro progetto.

Commenti

Qualsiasi suggerimento, contributo o commento sarà veramente apprezzato.