msgbartop
Blog di Dino Ciuffetti (Bernardino in realtà)
msgbarbottom

09 Mar 20 Disquisizioni su errori procedurali in ambito enterprise riguardo alla generazione e all’implementazione dei certificati SSL X509

Breve (anzi no) premessa senza entrare troppo nei dettagli di natura tecnica spinta. In sostanza i certificati X509 possono essere di varia natura e formato ma tutti governati dallo standard X.509 (https://en.wikipedia.org/wiki/X.509) che e’ uno standard internazionale. Secondo come vengono richiesti e poi emessi dalla CA competente (Certification Authority) hanno delle proprietà specifiche, alcune obbligatorie ed altre che cambiano in base alle applicazioni.

La crittografia asimmetrica basasta su certificati X.509 permette la mutua autenticazione (il client verifica il server e viceversa), cripta il canale di comunicazione impedendo il “man in the middle” ovvero rende impossibile per un attore che non conosce le chivi private client e server di poter “sniffare” il traffico mettendosi in mezzo, e conferma la veridicita’ e inalterabilita’ del messaggio in transito, oltre a verificare in modo inequivocabile chi l’ha inviato.

Per generare un certificato vi è sempre necessità di utilizzare una chiave privata (che va sempre tenuta segreta in quanto essa e’ in grado tra l’altro di decifrare i messaggi!). Operativamente e’ possibile generare una nuova chiave privata qualora quella precedente venga compromessa, oppure se si vuole cambiarla per motivi di sicurezza in generale, o ancora se viene richiesto dalla CA competente. Esse possono essere inaccessibili (ad esempio immagazzinate all’interno di una smartcard, un token di autenticazione, un wallet, etc) oppure accessibili. Nel caso fossero accessibili possono essere cifrate (protette da passphrase) oppure in chiaro. In base alla tecnologia su cui e’ implementata la PKI (Public Key Infrastructure) le chiavi possono essere salvate in un file (protetto contro letture non abilitate), un database, etc, ma solitamente non e’ altro che un contenitore come ad esempio un PKCS#12, un PKCS#8, un KeyStore Java (JKS), un Wallet Oracle, IBM, etc, etc.
E’ necessario, come appena detto, utilizzare una private key per generare un nuovo certificato, e questo viene fatto mediante la generazione di una richiesta di certificazione (CSR: Certification Signing Request, anche conosciuto come PKCS#10) che va inoltrata alla CA competente. Sebbene sia possibile generarsi un certificato da soli (self signed certificate) questa NON va considerata buona prassi ma bisognerebbe sempre utilizzare un Ente Certificatore preposto allo scopo. Il PKCS#10 contiene tutte le informazioni che servono alla CA per poter emettere un certificato X.509 valido e verificare in seguito che il richiedente sia quello corretto e il certificato “faccia scopa” con la chiave privata (per mezzo della firma digitale apposta dal richiedente per mezzo della sua chiave privata). Infatti, la chiave privata e il certificato che ne deriva hanno SEMPRE lo stesso “modulo”, cosa MAI vera se il certificato NON deriva da quella chiave privata ma da un’altra. E’ quindi possibile verificare che un determinato certificato derivi da una particolare chiave privata. Da un certificato non e’ possibile ottenere, ovviamente, una chiave privata, altrimenti tutto sarebbe inutile.

Una volta generato il CSR e il conseguente certificato la chiave privata NON va assolutamente buttata ma conservata in modo sicuro e configurata dove serve: senza di essa il certificato sarà completamente inutile e bisognerà rigenerarne un altro con una nuova chiave privata.

A seconda delle varie applicazioni e’ necessario, come sappiamo, implementare e scambiarsi uno o piu’ certificati SSL. Le chiavi private NON si scambiano mai!
Per quello che ci interessa in questa istanza, possiamo identificare le seguenti caratteristiche:

CERTIFICATO SERVER
 |caso 1|–> INSTALLATO SU UN SERVER (apache, tomcat, bea, etc): viene esposto su un server per implementare, ad esempio, il protocollo TLS con le relative ciphersuite. Il server invia il proprio certificato in fase di handshake per poter essere riconosciuto dal client che effettua la richiesta. Configurato come tale ha sempre bisogno della relativa chiave privata (come detto non una a caso ma esattamente quella che e’ stata utilizzata per la generazione e la firma del CSR) ed infatti per le tecnologie basate su java viene conservato nel cosiddetto KeyStore (ad esempio su tomcat e’ puntato dall’attributo keystoreFile nel connettore).
 |caso 2|–> INSTALLATO SU UN CLIENT: il certificato server viene utilizzato dal client per considerare TRUSTED (viene data fiducia) al server in fase di handshake. In questo caso non vi e’ alcun bisogno della chiave privata e infatti chi gestisce il server e ce lo invia la manterra’ privata. Nelle tecnologie java questi certificati vengono inseriti nel cosiddetto TrustStore (come ad esempio il cacerts della JVM).

CERTIFICATO CLIENT
 |caso 3|–> INSTALLATO SU UN CLIENT (ad esempio un browser, ma piu’ solitamente un’applicazione come Apache Axis, un client di una API, un client webservice o un reverse proxy come apache per la sua componente client – guardare ad es. direttiva SSLProxyMachineCertificateFile): viene esposto su un client per implementare la mutua autenticazione. In tal caso il client viene configurato per pubblicare il suo certificato al server in fase di handshake per poter essere riconosciuto dal server. Se configurato come tale ha sempre bisogno della relativa chiave privata (come detto non una a caso ma esattamente quella che e’ stata utilizzata per la generazione e la firma del CSR). Anche in questo caso, come per un certificato server installato su un server (caso 1), il certificato e la relativa chiave privata vanno in un KeyStore (in questo caso non del middleware ma dell’applicazione).
 |caso 4|–> INSTALLATO SU UN SERVER: il certificato client viene utilizzato dal server per considerare TRUSTED (viene data fiducia) al client in fase di handshake, come succede per un certificato server installato su un client (caso 2). Anche in questo caso la chiave privata non serve perche’ chi ce la invia (il client) la mantiene privata. Su tecnologie java, anche in questo caso, il certificato va installato nel TrustStore (in questo caso solitamente dell’applicazione o della JVM).

In tutte e 4 le casistiche indicate, i certificati non vanno installati da soli ma sempre completi della catena di certificazione (detto Chain of Trust), ovvero insieme al certificato della CA che lo ha emesso e nel caso di una CA Intermedia vanno installati tutti i certificati delle varie CA fino a quello della ROOT CA (la prima della catena). Se c’e’ un ordine questo deve procedere dal certificato utente fino a quello della ROOT CA che va installato per ultimo.

Da questo ne conseguono i seguenti punti di interesse di operation:
1) il trustStore NON ha mai chiavi private al suo interno ma solo certificati della controparte da autenticare (se sono server avro’ i certificati dei client, se sono client avro’ i certificati dei server).
2) l’applicazione puo’ usare piu’ trustStore e se e’ scritta in java vince il trustStore cacerts dentro “jre/lib/security/”
3) il keyStore avra’ il certificato con relativa chiave privata e non avra’ i certificati della controparte.
4) l’inserimento nel trustore e nel keystore prevede l’inserimento di tutta la catena di certificazione, ovvero i certificati delle varie CA
5) le operazioni per richiedere alla CA un certificato server o uno client sono le medesime, ma la CA scolpirà all’interno del certificato lo scopo per cui esso viene rilasciato (solo client, solo server o client/server). Diventa quindi importante richiedere alla CA la giusta tipologia di certificato perche’ il server o il client possono/devono verificare il corretto scopo del certificato.
6) sono previste le 4 diverse configurazioni del client e del server indicate sopra. Queste si differenziano nel caso in cui devono solo trustare le controparti (sia essa client o server, quindi senza chiave privata, ovvero i casi 2 e 4) oppure nel caso in cui si debba implementare il servizio vero e proprio (sia esso client o server, con chiave privata, ovvero i casi 1 e 3), con o senza mutua autenticazione
7) se non e’ prevista la mutua autenticazione il client non ha mai bisogno di un keyStore (certificato con chiave privata) ma solo di un trustStore per verificare il server. Nel caso di alcuni middleware o applicazioni non serve neanche quest’ultimo.
8) per un server il discorso e’ opposto, ovvero il server ha sempre e comunque bisogno di un keyStore ma se non c’e’ mutua autenticazione non ha bisogno di un trustStore per verificare il client.
9) le applicazioni o i middleware client e server possono essere configurati e/o implementati per verificare nel modo piu’ disparato e piu’ o meno strettamente i certificati della controparte. Posso ad esempio ignorare che un certificato della controparte sia scaduto o posso comunque fidarmi del certificato della controparte a prescindere che esso sia trustato nel mio truststore e posso ignorare completamente gli attributi del certificato e fidarmi comunque. Oppure invece posso andare a leggere e controllare scrupolosamente e puntualmente il certificato della controparte e verificare, ad esempio, una o piu’ cose tra cui: il seriale del certificato, il suo ente certificatore, il suo scopo, la scadenza, la scadenza del certificato della CA, il CN con cui viene pubblicato, se e’ stato revocato dalla CA (su richiesta del richiedente perche’ magari e’ stata compromessa la private key, oppure dalla ca stessa perche’ magari non si fidano piu’ dell’algoritmo di firma o delle procedure di rilascio, etc), se gli attributi di scopo sono rispettati (solo server, solo client, client/server, solo CA, solo firma digitale, etc), se il certificato e’ distribuito per una lista di nomi (SAN) o per un nome solo e essi fanno scopa con il servizio, etc, etc, etc.

Ne consegue quindi che le configurazioni possono essere molto personalizzate e flessibili e testare tutte le casistiche possibili non e’ fattibile. Forse la cosa migliore e’ lavorare a livello di documentazione, specialmente sulle procedure del singolo progetto.

In linea di massima possiamo riassumere le seguenti macro procedure di operation per le casistiche indicate sopra. Essendoci diverse tecnologie le modalita’ operative sono molto diverse nella forma ma uguali nella sostanza:

DEVO IMPLEMENTARE UN SERVER:
1) genero una chiave privata o uso quella precedente se la CA me lo consente (soddisfando i requisiti dettati da CA, esempio RSA 2048 bit)
2) genero un CSR a partire dalla chiave al punto 1 impostando nella richiesta tutti i parametri corretti (CN, scopo server, OU corretto, stato, paese, etc)
3) invio il CSR alla CA di competenza
4) ottengo il certificato solo server oppure client/server dalla CA
5) imposto il mio certificato sul keystore del server di cui sono responsabile insieme alla chiave privata al punto 1 e insieme ai certificati delle CA che lo hanno emesso
6) invio il mio certificato e quello della CA alle controparti SENZA inviare la chiave privata.
SE DEVO ATTIVARE MUTUA AUTENTICAZIONE (OVVERO FORZARE LA VERIFICA DEL CERTIFICATO CLIENT DELLA CONTROPARTE) FARO’ ANCHE QUESTE:
7) richiedo il certificato della controparte
8) inserisco nel mio truststore client o server il certificato della controparte e lo rendo TRUSTED insieme alle loro CA
9) forzo sul middleware le verifiche sui certificati appena messi nel truststore o implemento dei blocchi piu’ restrittivi, ad esempio controllando bene i certificati delle controparti affinche’ rispettino i requisiti di sicurezza richiesti dal progetto

DEVO IMPLEMENTARE UN CLIENT:
  di norma non serve fare nulla se non e’ richiesta mutua autenticazione. In alcune tecnologie, come ad esempio quelle basate su java potrei dover comunque effettuare i punti 1 e 2 indicati sotto:
SE DEVO ATTIVARE MUTUA AUTENTICAZIONE (OVVERO FORZARE LA VERIFICA DEL CERTIFICATO SERVER DELLA CONTROPARTE):
1) ottengo il certificato server dalla controparte
2) in base al middleware e alla tecnologia lo considero trusted sul mio truststore
3) genero una chiave privata o uso quella precedente se la CA me lo consente (soddisfando i requisiti dettati da CA, esempio RSA 2048 bit)
4) genero un CSR a partire dalla chiave al punto 1 impostando nella richiesta tutti i parametri corretti (CN, scopo client, OU corretto, stato, paese, etc)
5) invio il CSR alla CA di competenza
6) ottengo il certificato solo client oppure client/server dalla CA
7) imposto il mio certificato sul keystore del client di cui sono responsabile insieme alla chiave privata al punto 1 e insieme ai certificati delle CA che lo hanno emesso
8) invio il mio certificato e quello della CA alle controparti SENZA inviare la chiave privata
9) forzo sul middleware o sull’applicazione le verifiche sui certificati appena messi nel truststore o implemento dei blocchi piu’ restrittivi, ad esempio controllando bene i certificati delle controparti affinche’ rispettino i requisiti di sicurezza richiesti dal progetto

La maggior parte degli errori, per esperienza, avviene a livello procedurale perche’ spesso chi effettua l’attivita’ non ha la chiara visibilita’ o competenza su tutto il “giro del fumo”, oppure perche’ le informazioni si perdono (ad esempio in caso di passaggio di consegne). Per lo stesso motivo, in caso di disservizio, diventa lungo anche per noi di TS identificare il problema, non conoscendo bene tutte le applicazioni possibili.

Gli errori piu’ frequenti, comunque, risultano essere:

1) un mio certificato (server o client) scade creando disservizio alle controparti;
2) un mio certificato (server o client) viene (ri)generato con le modalita’ non corrette rispetto ai requisiti di progetto creando disservizio alle controparti
3) un certificato (server o client) di una controparte scade e mi crea un disservizio;
4) un certificato (server o client) di una controparte viene (ri)generato con le modalita’ non corrette rispetto ai requisiti di progetto e mi crea un disservizio
5) (ri)genero un certificato e non lo invio alle controparti, appena entra in campo potrei creare disservizio alle controparti
6) una controparte (ri)genera un certificato e non me lo invia, appena entra in campo potrei avere un disservizio
7) potrei per errore inviare alle controparti un certificato sbagliato, magari vecchio o di un altro progetto creando disservizio alle controparti
8) potrei ricevere per errore da una controparte un certificato sbagliato, magari vecchio o di un altro progetto ottenendo un disservizio
9) potrei inviare un certificato corrotto
10) potrei ricevere un certificato corrotto
11) essendoci vari formati (JKS, PEM, DER, P12, PFX, etc) potrei inviare un certificato in un formato che non si aspettano
12) potrei ricevere un certificato in un formato che non mi aspetto

Ricapitolando quindi, sia che ottengo, sia che sto inviando un certificato, esso deve sempre:
1- essere in corso di validita’ (non scaduto)
2- rispettare i requisiti di progetto (CN giusto, formato giusto, CA giusta, SAN, scopo, paese, attributi, etc)
3- essere installato e configurato correttamente sul mio middleware, sulla mia applicazione o su quelle di tutte le controparti

Il caso 1 e’ facilissimo da verificare e da prevedere, basta scaricarsi il certificato e verificare la data di scadenza;
Per il caso 2 bisogna verificare che il certificato faccia scopa con una serie di regole dettate dal singolo progetto o dalla singola tecnologia, volendo e’ possibile verificarlo rispetto ad uno che precedentemente andava bene e far saltare all’occhio le eventuali differenze perche’ potrebbero provocare un probabile disservizio;
Anche per il punto 3 la modalita’ di verifica cambia in base alla tecnologia o al progetto: se si tratta di un server si potrebbe invocare il servizio e prendersi il certificato esposto e verificarlo con le specifiche del progetto o con le proprieta’ di base che ci aspetteremmo da quel certificato. Se c’e’ mutua autenticazione il server potrebbe non risponderci fino a che non gli inviamo un certificato client valido che lui considera attendibile. Se invece e’ un client non si puo’ verificare da remoto ma solo in locale sulla macchina conoscendo il path ed avendo i giusti privilegi di accesso.

Allo stato attuale è possibile preparare uno shell script che permette di verificare visivamente un certificato X509, sia locale che remoto, e di mostrare tutte le sue proprieta’ e la data di emissione e scadenza.

Da qui a scriptare per risolvere i punti 2 e 3 la vedo molto complicata perche’ i requisiti e le tecnologie sono tutte diverse…

Ho completamente tralasciato tutto quello che riguarda i protocolli e le ciphersuite perche’ quello e’ un altro capitolo e la disquisizione e’ gia’ troppo lunga!

Buon Certificato X509 a tutti!

Lascia un commento

*