(Italiano) Approfondimento sullo standard PKCS#11 e utilizzo con Smart Card

Sorry, this entry is only available in Italiano.

Introduzione a PKCS#11

PKCS#11 (Public-Key Cryptography Standards #11), noto anche come Cryptographic Token Interface Standard, è uno standard sviluppato da RSA Laboratories. Esso definisce un’API (Application Programming Interface) indipendente dalla piattaforma per l’accesso a dispositivi di sicurezza hardware come token crittografici, HSM (Hardware Security Modules) e, soprattutto, Smart Card.

L’obiettivo principale dello standard PKCS#11 è fornire un’interfaccia unificata che consenta alle applicazioni di accedere a chiavi crittografiche e altre operazioni crittografiche senza dover gestire direttamente i dettagli del dispositivo sottostante.

In questo articolo esploreremo i concetti chiave di PKCS#11 e come utilizzarlo per firmare e verificare la firma di un messaggio tramite una Smart Card che in questo caso sarà la "nostrana" TS-CNS (Tessera Sanitaria - Carta Nazionale Servizi).

PKCS#11 e le Smart Card

Le Smart Card sono dispositivi fisici che memorizzano in modo sicuro chiavi crittografiche e certificati. Sono utilizzate in una vasta gamma di applicazioni, come la firma digitale, l’autenticazione e la crittografia dei dati. Lo standard PKCS#11 permette alle applicazioni di interfacciarsi con queste Smart Card in maniera sicura e trasparente.

Vantaggi dell'uso delle Smart Card con PKCS#11

  1. Sicurezza Hardware: le Smart Card sono dotate di un chip che esegue tutte le operazioni crittografiche, proteggendo le chiavi private dall’essere esposte al sistema host.
  2. Portabilità: poiché le chiavi sono memorizzate fisicamente sulla Smart Card, possono essere trasportate in sicurezza e utilizzate su diversi sistemi semplicemente inserendo la carta nel lettore.
  3. Indipendenza dalla piattaforma: grazie a PKCS#11, le applicazioni possono accedere alle funzionalità crittografiche della Smart Card senza dover implementare codice specifico per ogni dispositivo o sistema operativo.

Architettura e concetti chiave di PKCS#11

PKCS#11 è progettato per gestire una vasta gamma di dispositivi crittografici. Definisce una serie di oggetti e operazioni chiave che permettono alle applicazioni di interagire con i token crittografici come le Smart Card. Vediamo alcuni concetti chiave:

  1. Slot e Token: uno slot rappresenta l’interfaccia fisica o logica con il dispositivo crittografico (ad esempio, un lettore di Smart Card). Un token è il dispositivo crittografico stesso (ad esempio, la Smart Card inserita nello slot).
  2. Sessioni e Oggetti: le applicazioni aprono delle sessioni con il token per eseguire operazioni crittografiche. Gli oggetti memorizzati sul token possono essere chiavi crittografiche, certificati, o dati generici.
  3. Meccanismi Crittografici: PKCS#11 supporta diversi meccanismi crittografici, inclusi RSA, ECC, AES, e SHA, rendendolo flessibile per diverse applicazioni.
  4. Chiavi e Certificati: le Smart Card utilizzano chiavi private per la firma digitale o l’autenticazione. Le chiavi pubbliche e i certificati associati possono essere archiviati sulla Smart Card e resi disponibili tramite PKCS#11.

Crittografia a chiave asimmetrica: il classico esempio di Alice e Bob

La crittografia a chiave asimmetrica è un metodo di crittografia che utilizza due chiavi differenti: una chiave pubblica e una chiave privata. Queste due chiavi sono matematicamente collegate tra loro, ma non è possibile risalire alla chiave privata conoscendo solo la chiave pubblica. Cerchiamo di capire in modo semplice come funziona.

  • Chiave Pubblica: può essere condivisa pubblicamente con chiunque. Serve per cifrare i messaggi che solo il proprietario della corrispondente chiave privata può decifrare.
  • Chiave Privata: deve essere mantenuta segreta. Viene usata per decifrare i messaggi cifrati con la chiave pubblica e per firmare digitalmente i dati.

Facciamo il classico esempio di Alice e Bob. Immaginiamo quindi, Alice e Bob, che vogliono comunicare in modo sicuro utilizzando la crittografia a chiave asimmetrica.

  1. Scambio delle Chiavi:

    • Alice e Bob generano ciascuno una coppia di chiavi: una chiave pubblica e una chiave privata.
    • Alice invia la sua chiave pubblica a Bob.
    • Bob invia la sua chiave pubblica ad Alice.
  2. Alice invia un messaggio cifrato a Bob:

    • Alice utilizza la chiave pubblica di Bob per cifrare un messaggio.
    • Solo Bob, con la sua chiave privata, può decifrare il messaggio.
  3. Bob invia un messaggio firmato ad Alice:

    • Bob può firmare un messaggio con la sua chiave privata.
    • Alice può verificare l’autenticità del messaggio usando la chiave pubblica di Bob.
sequenceDiagram participant Alice participant Bob Alice->>Bob: Richiesta chiave pubblica Bob-->>Alice: Invia chiave pubblica Alice->>Alice: Cifra il messaggio con la chiave pubblica di Bob Alice->>Bob: Invia messaggio cifrato Bob->>Bob: Decifra il messaggio con la sua chiave privata Bob->>Alice: Richiesta chiave pubblica Alice-->>Bob: Invia chiave pubblica Bob->>Bob: Firma il messaggio con la chiave privata Bob->>Alice: Invia messaggio firmato Alice->>Alice: Verifica la firma con la chiave pubblica di Bob

Figura 1 - Sequence Diagram di come Alice e Bob si scambiano un messaggio cifrato e firmato utilizzando le chiavi asimmetriche.

Ora, cerchiamo di capire una differenza importante, ovvero, quella esistente tra cifrare un messaggio e firmare un messaggio.

La cifratura e la firma digitale sono due concetti fondamentali della crittografia, ma servono a scopi diversi: la cifratura protegge la riservatezza di un messaggio, mentre la firma digitale garantisce autenticità e integrità.

Cifrare un Messaggio

Obiettivo: proteggere il contenuto del messaggio, mantenendolo segreto e accessibile solo al destinatario autorizzato.

Come funziona:

  • Chiave pubblica del destinatario: usata per cifrare il messaggio.
  • Chiave privata del destinatario: usata per decifrare il messaggio.

Usando l'approccio della cifratura asimmetrica:

Se Alice vuole inviare un messaggio segreto a Bob, Alice cifra il messaggio con la chiave pubblica di Bob. Solo Bob, con la sua chiave privata, potrà decifrare il messaggio e leggerne il contenuto.

Questo garantisce che nessun altro possa leggere il messaggio, mantenendo la riservatezza.

Esempio:

Immagina che Alice invii un'email a Bob con informazioni sensibili. Alice cifra il contenuto con la chiave pubblica di Bob. Anche se qualcun altro intercettasse l'email, non potrebbe decifrarla senza la chiave privata di Bob.

Firmare un Messaggio

Obiettivo: garantire che il messaggio provenga realmente dal mittente (autenticità) e che non sia stato alterato (integrità).

Come funziona:

  • Chiave privata del mittente: usata per firmare digitalmente il messaggio.
  • Chiave pubblica del mittente: usata dal destinatario per verificare la firma.

Usando l'approccio della firma asimmetrica:

Se Bob vuole inviare un messaggio firmato ad Alice, Bob firma il messaggio con la sua chiave privata. Alice può verificare la firma utilizzando la chiave pubblica di Bob. Se la verifica riesce, Alice sa che il messaggio è autentico (proviene da Bob) e non è stato alterato durante il trasporto (integrità).

Esempio:

Immagina che Bob invii un contratto digitale ad Alice e lo firmi digitalmente con la sua chiave privata. Alice può verificare la firma con la chiave pubblica di Bob per essere sicura che il documento sia stato inviato da Bob e non sia stato modificato.

La tabella a seguire mostra in modo schematico le differenze tra la cifratura e la firma digitale.

AspettoCifraturaFirma Digitale
ScopoProteggere la riservatezza del messaggioGarantire l'autenticità e l'integrità del messaggio
Chiave usataChiave pubblica del destinatario per cifrareChiave privata del mittente per firmare
Chiave per verificareChiave privata del destinatario per decifrareChiave pubblica del mittente per verificare
RisultatoSolo il destinatario può leggere il messaggioIl destinatario può verificare la provenienza e l'integrità del messaggio
Tabella 1 - Differenza tra cifratura e firma digitale

Per fare un riepilogo:

  • cifrare serve a proteggere i dati, garantendo che solo il destinatario previsto possa leggere il messaggio.
  • firmare serve a garantire autenticità e integrità, confermando che il messaggio proviene dal mittente e non è stato modificato.

In pratica, queste tecniche vengono spesso utilizzate insieme per fornire sicurezza completa: si può cifrare un messaggio per mantenerlo privato e firmarlo digitalmente per garantirne l'autenticità e l'integrità.

Il limite principale della crittografia asimmetrica risiede nelle prestazioni. La crittografia asimmetrica è più lenta rispetto a quella simmetrica, per cui spesso viene usata insieme alla crittografia simmetrica per cifrare dati più grandi.

Esempio pratico con PKCS#11 e Smart Card

Vediamo ora un esempio pratico di come utilizzare PKCS#11 per accedere a una Smart Card e eseguire operazioni di firma digitale.

Requisiti

Per portare a termine questo esempio, avremo bisogno degli elementi a seguire.

  1. Una Smart Card compatibile con PKCS#11.
  2. Un certificato digitale per la tua Smart Card.
  3. Un PIN per accedere alla Smart Card.
  4. Un lettore di Smart Card.
  5. Un driver PKCS#11 per la tua Smart Card.
  6. Un ambiente di sviluppo per il linguaggio di programmazione che desideri utilizzare.
  7. Un'API PKCS#11 per il tuo linguaggio di programmazione.
  8. Un'applicazione che utilizzi PKCS#11 per accedere alla Smart Card.
  9. Un ambiente di test per eseguire l'applicazione.

In commercio esistono diverse Smart Card compatibili con PKCS#11 ma in questo esempio ho volutamente scelto di usare una Smart Card che credo abbiate tutti (o quasi): la TS-CNS (Tessera Sanitaria - Carta Nazionale Servizi).

Nota: prima di poter usare il nostro certificato digitale della TS-CNS, è necessario provvedere alla sua attivazione. Sul portale STS (Sistema Tessera Sanitaria) è possibile trovare tutte le informazioni necessarie per attivare la propria TS-CNS, più altre funzionalità, come per esempio la consultazione delle spese sanitarie. Ogni regione prevede modalità diverse per l'attivazione della TS-CNS, quindi è importante seguire le istruzioni specifiche per la propria regione. Nel caso della regione Lazio è possibile attivare la TS-CNS direttamente presso gli sportelli ASL di appartenenza. Per ulteriori informazioni, è possibile consultare il sito ufficiale della Regione Lazio nella sezione Come attivate la Carta Nazionale dei Servizi.

Per quanto riguarda il lettore di Smart Card, è possibile utilizzare un lettore USB o integrato nel computer. Personalmente ho utilizzato il lettore USB miniLector EVO prodotto da bit4id.

Per quanto riguarda il driver PKCS#11, è possibile utilizzare quello fornito dal produttore della Smart Card o utilizzare un driver open source come OpenSC. Per questo esempio ho utilizzato OpenSC, principalmente perché è open source e supporta una vasta gamma di Smart Card, tra cui la TS-CNS (basta eseguire il comando opensc-tool -c '?'per ottenere la lista dei driver tra cui è presente anche itacns - Italian CNS). Da non dimenticare che OpenSC è disponibile per diverse piattaforme, tra cui Linux, macOS e Windows.

Sul linguaggio di programmazione non c'è limite di scelta, in quanto PKCS#11 è supportato da diversi linguaggi di programmazione, tra cui C, C++, Java, Python, ecc. In questo esempio, la scelta ricade su Python, linguaggio molto popolare e facile da usare, soprattutto per chi è alle prime armi con la programmazione.

Le API PKCS#11 per Python sono disponibili tramite il modulo PyKCS11, che fornisce un'interfaccia per l'API PKCS#11. Per installare PyKCS11, è possibile utilizzare il gestore di pacchetti pip eseguendo il comando pip install PyKCS11.

Assodato che faremo uso di Python, PyKCS11 e OpenSC per portare a termine questo esempio, il mio ambiente di sviluppo e test è composto da: macOS, Python 3.12.6, PyKCS11 1.5.16 e OpenSC 0.25.1 [gcc Apple LLVM 15.0.0 (clang-1500.3.9.4)]. Ovviamente, per chi volesse replicare l'esempio su Windows o Linux, basta installare le versioni di Python, PyKCS11 e OpenSC compatibili con il proprio sistema operativo.

A questo punto che abbiamo soddisfatto tutti i requisiti, è giunto il momento di mettere le mani al codice andando a implementare un semplice programma che eseguirà un'operazione di firma digitale usando il nostro certificato presente all'interno della TS-CNS.

Implementazione dell'applicazione

Andremo a realizzare una semplice applicazione che implementa il flusso dove Bob firma un messaggio e Alice verifica la firma (vedi Figura 1). Il programma sarà diviso in due parti: una per la firma digitale (blocco che dovrebbe usare Bob) e una per la verifica della firma (blocco che dovrebbe usare Alice). In questo esempio, utilizzeremo la chiave privata della TS-CNS per firmare il messaggio e la chiave pubblica per verificare la firma.

Non entreremo nel dettaglio di come funziona l'API PKCS#11, ma ci concentreremo sull'utilizzo pratico per firmare e verificare la firma. Lascio a voi la curiosità di approfondire l'API PKCS#11 e come funziona consultando la documentazione ufficiale e la documentazione di PyKCS11.

Nota: Quelli che mostrerò a seguire sono gli snippet di codice per firmare e verificare la firma. Il codice completo è disponibile su GitHub.

Procediamo per step. Il primo passo è inizializzare l'API PKCS#11 e ottenere un handle per la Smart Card. Per far ciò, dobbiamo importare il modulo PyKCS11 e creare un oggetto PyKCS11.PyKCS11Lib con il percorso del driver PKCS#11 della nostra Smart Card.

import PyKCS11

# Percorso della libreria PKCS#11
pkcs11_lib_path = '/opt/homebrew/Cellar/opensc/0.25.1/lib/opensc-pkcs11.so'
if not os.path.exists(pkcs11_lib_path):
   raise PKCS11LibraryNotFound(
      f"Libreria PKCS#11 non trovata. Specifica il percorso manualmente. Percorso attuale: {pkcs11_lib_path}")

# Carica la libreria PKCS#11
pkcs11 = PyKCS11.PyKCS11Lib()
pkcs11.load(pkcs11_lib_path)
Python

Source Code 1 - Inizializzazione dell'API PKCS#11 e caricamento della libreria PKCS#11

Il secondo passo è quello di ottenere lo slot e il token della Smart Card. Dopo aver ottenuto lo slot e il token, possiamo aprire una sessione con la Smart Card e autenticarci con il PIN.

    # Ottieni la lista degli slot con token presenti
    slots = pkcs11.getSlotList(tokenPresent=True)

    if len(slots) == 0:
        raise NoSmartCardInserted("Nessuna Smart Card inserita")

    # Usa il primo slot disponibile
    slot = slots[0]

    # Apri una sessione con la Smart Card
    session = pkcs11.openSession(slot)
    session.login(args.pin)
Python

Source Code 2 - Ottenimento dello slot e del token della Smart Card e apertura di una sessione con la Smart Card

Il terzo passo consiste nel caricare la chiave privata per la firma e la chiave pubblica per la verifica della firma. Per fare ciò, dobbiamo ottenere gli oggetti chiave dalla Smart Card utilizzando il loro ID (vedi PyKCS11.CKO_PRIVATE_KEY, PyKCS11.CKO_CERTIFICATE e PyKCS11.CKA_VALUE).

In questo caso siamo certi del fatto che sulla TS-CNS abbiamo un solo certificato e una sola chiave privata, possiamo quindi assumere che in posizione [0] troveremo i nostri oggetti.

    # Trova la chiave privata sulla Smart Card
    private_key = session.findObjects([(PyKCS11.CKA_CLASS, PyKCS11.CKO_PRIVATE_KEY)])[0]

    # Trova il certificato pubblico sulla Smart Card
    public_cert = session.findObjects([(PyKCS11.CKA_CLASS, PyKCS11.CKO_CERTIFICATE)])[0]

    # Ottieni il certificato pubblico in formato DER
    public_cert_der = session.getAttributeValue(public_cert, [PyKCS11.CKA_VALUE], False)[0]
    public_cert_der = bytes(public_cert_der)

    # Carica il certificato pubblico
    cert = x509.load_der_x509_certificate(public_cert_der, backend=default_backend())

    # Ottieni la chiave pubblica dal certificato
    public_key = cert.public_key()
Python

Source Code 3 - Caricamento della chiave privata e pubblica dalla Smart Card

Il quarto passo prevede la codifica del messaggio e la sua firma. Per firmare il messaggio, dobbiamo utilizzare la chiave privata e un algoritmo di firma come PyKCS11.CKM_SHA256_RSA_PKCS.

    # Codifica il messaggio da firmare
    data = args.message.encode()

    # Firma il messaggio usando la chiave privata
    mechanism = PyKCS11.Mechanism(PyKCS11.CKM_SHA256_RSA_PKCS, None)
    signature = session.sign(private_key, data, mechanism)
    signature = bytes(signature)
Python

Source Code 4 - Codifica del messaggio e firma del messaggio

A questo punto abbiamo ottenuto la firma del messaggio (signature = bytes(signature)) che Bob vuole inviare ad Alice. Come ultimo passo, dobbiamo scrivere il blocco di codice che Alice dovrebbe usare per verificare che il messaggio sia stato firmato da Bob.

   # Verifica la firma usando la chiave pubblica
   try:
      public_key.verify(
         signature,
         data,
         padding.PKCS1v15(),
         hashes.SHA256()
      )
      print(f"{Fore.GREEN}✅ Firma verificata correttamente!")
   except Exception as e:
      print(f"{Fore.RED}❌ Verifica della firma fallita: {e}")
   
   # Logout dalla sessione
   session.logout()
Python

Source Code 5 - Verifica della firma del messaggio

Wow! Abbiamo completato l'implementazione dell'applicazione che esegue un'operazione di firma digitale e verifica della firma utilizzando una Smart Card e l'API PKCS#11. Per fare un riepilogo e inserire nel contesto Bob e Alice, quello che dovrebbe accadere e quanto mostrato dal sequence diagram a seguire.

sequenceDiagram participant Bob participant SmartCard participant Alice Bob->>SmartCard: Inserisce la Smart Card Bob->>SmartCard: Inserisce il PIN SmartCard-->>Bob: Autenticazione riuscita Bob->>SmartCard: Firma il messaggio SmartCard-->>Bob: Restituisce la firma Bob->>Alice: Invia messaggio e firma Alice->>Bob: Chiede a Bob la chiave pubblica Bob-->>Alice: Restituisce la chiave pubblica Alice->>Alice: Verifica la firma con la chiave pubblica Alice-->>Alice: Firma verificata correttamente

Figura 2 - Sequence Diagram di come Alice e Bob si scambiano un messaggio cifrato e firmato utilizzando le chiavi asimmetriche.

Conclusa la fase d'implementazione, passeremo alla fase di test.

Test dell'applicazione di firma digitale

L'applicazione finale è disponibile su GitHub e può essere eseguita da riga di comando. Per eseguire l'applicazione, è necessario specificare il PIN della Smart Card e il messaggio da firmare. Ecco un esempio di come eseguire l'applicazione:

# Installazione dei requirements
pip install -r requirements.txt

# Esegui l'applicazione per firmare un messaggio
./sign-via-ts-cns.py --pin 123456 --message "Prima firma di un messaggio tramite la mia TS-CNS"
Bash

Console 1 - Esempio di esecuzione dell'applicazione di firma digitale

In output l'applicazione mostrerà la firma generata (in formato esadecimale) e il risultato della verifica della firma. Se la firma è stata verificata correttamente, sarà visualizzato un messaggio di successo, altrimenti verrà visualizzato un messaggio di errore. A seguire un esempio di output dell'applicazione.

🔍 Dati da firmare: b'Prima firma di un messaggio tramite la mia TS-CNS'
✅ Firma generata (in esadecimale): b'99be876fb527dbd8e36e9d76f69357e6ef006c737e535b48ed45acd28ebb3b2a14cc7a08cc4902d92194b18b2cc8b61cc2a23747119b6c473fe4757e12ac66c6ce9488354a9fbbb95b003b643295e428b18383328192953c645afe0f9b00e9bf405981da4a52b40f288275023d8aa06e81f88a066888dc29e88a1b6280b5e7c2f26b1e8d5bc469839dcf07128b3e525ad88c9190b76811def76530131246e201a4428b74f65757957e67190ce284b0c8ee89f422b3cf960899467fd1bb66ded6a97999ccf3a2407b07f49af697590b0dac28585c5c3e8b0ca3b3aa1bc47eb1aab2d67a0b0fc1c8cf9bde51512acb9ebed80bf514f6cfe7e9900d2d3541df1f39'
✅ Firma verificata correttamente!
Plaintext

Console 2 - Esempio di output dell'applicazione di firma digitale

Quando l'applicazione termina con successo, questa genera tre file:

  1. message_<uuid4>txt: il messaggio originale.
  2. signature_<uuid4>.txt: la firma generata.
  3. public_cert.pem: la chiave pubblica.

Questi file possono essere utilizzati per verificare la firma in un secondo momento o per inviare il messaggio firmato ad altri utenti, come per esempio Alice. Quindi, per fare fede a quanto indicato del sequence diagram di Figura 2, Alice dovrebbe usare questi tre file per verificare la firma del messaggio.

Qual è il modo più semplice per verificare la firma del messaggio? Semplice, usando OpenSSL. Ecco come fare.

# Verifica la firma del messaggio tramite openssl.
openssl dgst -sha256 -verify <(openssl x509 -in public_cert.pem -pubkey -noout) -signature signature_e032b4fe6213486eb9830fe0dacf9f3b.bin message_9789a64270b1443da672a5d1776d6664.txt
Bash

Console 3 - Verifica della firma del messaggio tramite OpenSSL

Il risultato atteso dovrebbe essere Verified OK. Se la firma è stata verificata correttamente, significa che l'applicazione ha funzionato correttamente e che la firma è stata generata e verificata con successo.

Nel caso in cui la verifica della firma fallisca, è possibile che ci siano stati errori durante la generazione della firma o magari per qualche motivo per esempio il messaggio originale è stato alterato. Facciamo una simulazione di alterazione del messaggio originale e vediamo cosa succede.

# Altera il messaggio originale
echo "Messaggio alterato" > message_9789a64270b1443da672a5d1776d6664.txt

# Verifica la firma del messaggio tramite openssl.
openssl dgst -sha256 -verify <(openssl x509 -in public_cert.pem -pubkey -noout) -signature signature_e032b4fe6213486eb9830fe0dacf9f3b.bin message_9789a64270b1443da672a5d1776d6664.txt
Bash

Console 4 - Verifica della firma del messaggio tramite OpenSSL con messaggio alterato

Il risultato atteso dovrebbe essere Verification Failure. Se la verifica della firma fallisce, significa che il messaggio è stato alterato dopo la firma e quindi la firma non è più valida.

Il programma completo consente di fare anche altro, per scoprirlo basta eseguire il comando ./sign-via-ts-cns.py --help per visualizzare l'help dell'applicazione e dovreste vedere qualcosa di simile a quanto mostrato a seguire.

usage: sign-via-ts-cns.py [-h] --pin PIN --message MESSAGE [--debug] [--signature-file SIGNATURE_FILE] [--message-file MESSAGE_FILE]
                          [--pkcs11-lib PKCS11_LIB]

Script per firmare un messaggio usando una Smart Card

options:
  -h, --help            show this help message and exit
  --pin PIN             PIN della Smart Card
  --message MESSAGE     Messaggio da firmare
  --debug               Abilita i messaggi di debug
  --signature-file SIGNATURE_FILE
                        File in cui salvare la firma
  --message-file MESSAGE_FILE
                        File in cui salvare il messaggio
  --pkcs11-lib PKCS11_LIB
                        Percorso della libreria PKCS#11
Bash

Console 5 - Help dell'applicazione di firma digitale

L'opzione che mi sento di consigliare è --debug che abilita in output ulteriori messaggi utili a capire meglio cosa stia succedendo durante l'esecuzione dell'applicazione. Inoltre, è possibile specificare il percorso della libreria PKCS#11 con l'opzione --pkcs11-lib e i file in cui salvare la firma e il messaggio con le opzioni --signature-file e --message-file.

A seguire il diagramma di sequenza che mostra come l'applicazione interagisce con la Smart Card attraverso la libreria PKCS#11 per firmare un messaggio e verificare la firma.

sequenceDiagram participant User participant Script participant PKCS11Lib participant SmartCard User ->> Script: Avvia lo script con i parametri Script ->> Script: Analizza i parametri di input Script ->> PKCS11Lib: Carica la libreria PKCS#11 Script ->> PKCS11Lib: Ottiene la lista degli slot con token presenti PKCS11Lib -->> Script: Lista degli slot Script ->> SmartCard: Apre una sessione con la Smart Card Script ->> SmartCard: Esegue il login con il PIN Script ->> SmartCard: Trova la chiave privata SmartCard -->> Script: Chiave privata Script ->> SmartCard: Trova il certificato pubblico SmartCard -->> Script: Certificato pubblico Script ->> SmartCard: Ottiene il certificato pubblico in formato DER SmartCard -->> Script: Certificato pubblico (DER) Script ->> Script: Carica il certificato pubblico Script ->> Script: Salva il certificato pubblico in formato PEM Script ->> Script: Ottiene la chiave pubblica dal certificato Script ->> Script: Codifica il messaggio da firmare Script ->> SmartCard: Firma il messaggio usando la chiave privata SmartCard -->> Script: Firma Script ->> Script: Salva la firma su file Script ->> Script: Salva il messaggio su file Script ->> Script: Verifica la firma usando la chiave pubblica Script ->> SmartCard: Esegue il logout dalla sessione Script ->> User: Termina l'esecuzione

Figura 3 - Sequence Diagram di come l'applicazione interagisce con la Smart Card attraverso la libreria PKCS#11 per firmare un messaggio e verificare la firma

Utilizzo in applicazioni reali

Le Smart Card e lo standard PKCS#11 sono utilizzati in molti scenari di sicurezza crittografica.

  1. Firma Digitale: le firme digitali eseguite tramite chiavi private su Smart Card sono molto comuni in applicazioni di governo elettronico (e-government) e nei sistemi finanziari.
  2. Autenticazione Forte: molte aziende e istituzioni richiedono un’autenticazione a due fattori (2FA) basata su Smart Card per l’accesso ai sistemi critici.
  3. Crittografia e Decrittazione: le Smart Card possono essere utilizzate per cifrare e decifrare documenti o dati sensibili direttamente all’interno del dispositivo, garantendo che le chiavi private non lascino mai la carta.
  4. Infrastruttura PKI: le Smart Card sono comunemente utilizzate in un’infrastruttura a chiave pubblica (PKI) per la gestione sicura delle identità digitali.

Risorse e Approfondimenti

Il repository GitHub pkcs11-smart-card con il codice completo dell'applicazione è disponibile al seguente link.

Per ulteriori informazioni su PKCS#11 e PyKCS11, consiglio di consultare la documentazione ufficiale: PKCS#11 e PyKCS11.

Per ulteriori informazioni su OpenSC, consiglio di consultare la documentazione ufficiale: OpenSC.

Nel caso in cui si desideri approfondire la programmazione delle Smart Card, consiglio l'ottimo libro di Ugo Chirico Programmazione delle Smart Card.

Per altri temi che riguardano Smart Card e sicurezza informatica, propongo qualche articolo pubblicato sul mio blog personale:

  1. Raspberry Pi e Smart Card Mifare Classic 1K: Realizzare un sistema di accesso
  2. Implementazione di TLS Mutual Authentication (mTLS) con Quarkus
  3. Raspberry Pi – Un esempio di applicazione della TS-CNS

Conclusioni

Lo standard PKCS#11 rappresenta uno strumento potente e flessibile per integrare dispositivi crittografici hardware, come le Smart Card, all’interno di applicazioni moderne. Grazie a questa API standardizzata, gli sviluppatori possono sfruttare le capacità crittografiche avanzate dei token hardware in modo semplice e sicuro, indipendentemente dalla piattaforma sottostante.

In questo articolo, abbiamo esplorato i concetti chiave di PKCS#11 e come utilizzarlo per firmare e verificare la firma di un messaggio tramite una Smart Card. Abbiamo anche visto come sia stato semplice implementare un’applicazione Python che sfrutta l’API PKCS#11 per interagire con una Smart Card, in questo caso la "nostrana" TS-CNS ed eseguire operazioni di firma digitale.

Antonio Musarra

I began my journey into the world of computing from an Olivetti M24 PC (http://it.wikipedia.org/wiki/Olivetti_M24) bought by my father for his work. Day after day, quickly taking control until … Now doing business consulting for projects in the enterprise application development using web-oriented technologies such as J2EE, Web Services, ESB, TIBCO, PHP.

You may also like...