Spring & mutua autenticazione: verifica data di scadenza del certificato server

240 views
Skip to first unread message

Giuseppe Coniglio

unread,
Jul 8, 2022, 4:23:48 AM7/8/22
to JUG Torino - JVM User Group Torino
Ciao a tutti, ho sviluppato un progetto client che invoca un' API REST seguendo le indicazioni della pagina https://www.aurigait.com/blog/how-to-implement-2-way-ssl-using-spring-boot
Utilizzo un univo keystore che ha il certificato server  ed il mio certificato con la keypair

Il codice è il seguente:

  try {
            keyStore = KeyStore.getInstance("jks");
            ClassPathResource classPathResource = new ClassPathResource("client-app.jks");
            InputStream inputStream = classPathResource.getInputStream();
            keyStore.load(inputStream, myKeyStorePassword.toCharArray());

            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(new SSLContextBuilder()
                .loadTrustMaterial(null, new TrustSelfSignedStrategy())
                .loadKeyMaterial(keyStore, myKeyPassword.toCharArray()).build(),
                NoopHostnameVerifier.INSTANCE);

            HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory)
                .setMaxConnTotal(Integer.valueOf(5))
                .setMaxConnPerRoute(Integer.valueOf(5))
                .build();

            requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
            requestFactory.setReadTimeout(Integer.valueOf(10000));
            requestFactory.setConnectTimeout(Integer.valueOf(10000));

            restTemplate.setRequestFactory(requestFactory);
        }


Le chiamate al provider funzionano correttamente , non capisco perchè da oggi che è scaduto (ieri) il certificato server presente nel mio keystore tutte le chiamate continuano a funzionare correttamente e ricevo tutti i dati dal server.
Allego immagine, secondo voi dove si deve interrompere la comunicazione essendo scaduto il cer pubblico nel mio keystore, nel punto A oppure B ?
Chi espone il servizio mi risponde che siamo noi lato client che falliamo nella fase 2 con la "verifica del certificato server" in quanto questa operazione va eseguita dal client.
A me sembra che invece che il blocco dovrebbe avvenire lato server nella fase 3 (send encrypted with public key server), in quanto la chiave pubblica del sever (che inviamo nella fase 2) è scaduta ma il servizio del server ci ritorna i dati ugualmente.

Grazie tante
buona giornata :-)


Spring_MA.jpg

antonio caccamo

unread,
Jul 8, 2022, 10:05:57 AM7/8/22
to Giuseppe Coniglio, JUG Torino - JVM User Group Torino
Ciao,
a mio avviso il problema è il NoopHostnameVerifier

non viene fatta nessun tipo di verifica

Antonio

--
Hai ricevuto questo messaggio perché sei iscritto al gruppo "JUG Torino - JVM User Group Torino" di Google Gruppi.
Per annullare l'iscrizione a questo gruppo e non ricevere più le sue email, invia un'email a jugtorino+...@googlegroups.com.
Per visualizzare questa discussione sul Web, visita https://groups.google.com/d/msgid/jugtorino/7592389b-942a-4a3b-bf18-f09a03d773b7n%40googlegroups.com.

Giuseppe Coniglio

unread,
Jul 8, 2022, 10:22:21 AM7/8/22
to JUG Torino - JVM User Group Torino
" This hostname verifier essentially turns hostname verification off. It accepts any SSL session as valid and matching the target host" 

Penso riguardi il common name e non la data di scadenza o sbaglio?

Sto leggendo anche "  Important: hostname verification should not be confused with SSL trust verification."

Andrea Ligios

unread,
Jul 9, 2022, 5:34:24 PM7/9/22
to Giuseppe Coniglio, JUG Torino - JVM User Group Torino
Beppe, ma gli integration test ce li avete?

Mettete su il test che passa e quello che fallisce e la risolvete facile.

My 2 cents

Giuseppe Coniglio

unread,
Jul 10, 2022, 8:13:36 AM7/10/22
to Andrea Ligios, JUG Torino - JVM User Group Torino
Ciao André,
ma certo che abbiamo fatto i test, ma cosa scrivi?! :-D
Qua ho chiesto se qualcuno mi spiega bene con un codice di esempio java la 2two ssl con Spring quando miosito deve chiamare tuosito. 
Sul fatto di cosa deve avere il mio Jks usato è pacifico (vedi immagine postata e teoria che sappiamo a memoria ormai da anni), io sono il client e devo avere cer del server tuosito e la mia key pair (non self signed ovviamente)  del mio sito, ma il codice Java che fa la validazione di miosito che chiama tuosito qual è?
Sembra che si trova solo "disable ssl validation" con google... 
Tutti gli esempi trovati nel web riportano il codice che ho postato... 
Il fatto che me ne sono accorto perché, da un anno ha sempre funzionat, poi a fine mese scade il mio di certificato e quindi aprendo il mio keystore con Portecle vedo che ho il loro certificato é scaduto qualche giorno fa..
Quindi richiamo il loro servizio e nonostante mi presento con un loro cer scaduto mi ritornano i dati: come ho messo nell'immagine questo è dovuto ad un problema lato 'A' oppure 'B'? E come si fa eventualmente il controllo con Java di questi due punti (sia lato client quando sono A, sia lato server quando sono B visto che ho microservizi dove invece sono io il server provider)? 
Al che ho messo nel mio keystore il nuovo cer server fornitomi appunto e funziona ovviamente la chiamata ( se funzionava col vecchio figuriamoci col nuovo cer server)
Rimetto quindi nel mio keystore il vecchio cer server scaduto( togliendo quello nuovo) e e altro mistero nei log vedo nel dubug ssl  server con scadenza quella nuova della prova con il nuovo cer ( ovviamente nel cacert e jssecacerts del mio server Centos non ho alcun riferimento al cer del server). 
Qualcuno nel Jug ha sviluppato dei microservizi con Spring che fanno queste cose? 
Grazie 
Buona giornata :-) 

Simone Bordet

unread,
Jul 10, 2022, 10:17:23 AM7/10/22
to Giuseppe Coniglio, JUG Torino - JVM User Group Torino
Ciao,

On Fri, Jul 8, 2022 at 10:23 AM Giuseppe Coniglio <jackf...@gmail.com> wrote:
>
> Ciao a tutti, ho sviluppato un progetto client che invoca un' API REST seguendo le indicazioni della pagina https://www.aurigait.com/blog/how-to-implement-2-way-ssl-using-spring-boot
> Utilizzo un univo keystore che ha il certificato server ed il mio certificato con la keypair
>
> Il codice è il seguente:
>
> try {
> keyStore = KeyStore.getInstance("jks");
> ClassPathResource classPathResource = new ClassPathResource("client-app.jks");
> InputStream inputStream = classPathResource.getInputStream();
> keyStore.load(inputStream, myKeyStorePassword.toCharArray());
>
> SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(new SSLContextBuilder()
> .loadTrustMaterial(null, new TrustSelfSignedStrategy())
> .loadKeyMaterial(keyStore, myKeyPassword.toCharArray()).build(),
> NoopHostnameVerifier.INSTANCE);
>
> HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory)
> .setMaxConnTotal(Integer.valueOf(5))
> .setMaxConnPerRoute(Integer.valueOf(5))
> .build();
>
> requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
> requestFactory.setReadTimeout(Integer.valueOf(10000));
> requestFactory.setConnectTimeout(Integer.valueOf(10000));
>
> restTemplate.setRequestFactory(requestFactory);
> }
>
>
> Le chiamate al provider funzionano correttamente , non capisco perchè da oggi che è scaduto (ieri) il certificato server presente nel mio keystore tutte le chiamate continuano a funzionare correttamente e ricevo tutti i dati dal server.

Come fai a sapere che il certificato è scaduto?
Lo chiedi perché le istruzioni che riporti danno una durata dei
certificati di 10 anni.

> Allego immagine, secondo voi dove si deve interrompere la comunicazione essendo scaduto il cer pubblico nel mio keystore, nel punto A oppure B ?

Nel punto A.

> Chi espone il servizio mi risponde che siamo noi lato client che falliamo nella fase 2 con la "verifica del certificato server" in quanto questa operazione va eseguita dal client.

E' corretto.

> A me sembra che invece che il blocco dovrebbe avvenire lato server nella fase 3 (send encrypted with public key server), in quanto la chiave pubblica del sever (che inviamo nella fase 2) è scaduta ma il servizio del server ci ritorna i dati ugualmente.

No.

Non so come mai il controllo lato client non ti funziona, ma ho 2 teorie:
1) il certificato del server è a posto, anche se tu pensi di no
2) siccome hai il certificato del server nel client KeyStore, il
client lo usa per confrontarlo con quello del server, vede che sono
identici e quindi lo trusta anche se è scaduto.

Il setup indicato nel link che riporti non è il modo canonico di
impostare client certificate authentication.
Di solito il server certificate è firmato da una nota CA e quindi il
client non ha bisogno di nulla dal server (perché nella JVM ci sono
già tutti i certificati delle CA note).
Nel client c'è solo il certificato client da mandare al server per
l'autenticazione e di solito questo certificato è firmato dal server
(con un altro certificato che deve avere l'estensione ca:true), più
raramente il certificato del client è all'interno del keystore del
server (perché scala di meno).

Prova a impostare nel client -Djavax.net.debug=all e dovresti vedere i
vari passaggi e perché non hai nessun errore.

--
Simone Bordet
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless. Victoria Livschitz

Giuseppe Coniglio

unread,
Jul 10, 2022, 12:52:14 PM7/10/22
to Simone Bordet, JUG Torino - JVM User Group Torino
Ciao Simone ,
grazie per le info.

> "Come fai a sapere che il certificato è scaduto?"
come ho già spiegato , apro il mio jks con Portecle/KeyStore Explorer e si vede che il certificato Server è scaduto, in allegato l'immagine esplicativa.

> "Nel punto A."
quindi se io cambiassi le chiavi di casa ma non lo dico a mia moglie, deve essere lei che quando prova ad entrare in casa non riesce e quindi resta fuori tutta la notte , perfetto   :-)  quale codice Java fa i controlli del punto A? (in questo caso sono io il client ma quando sono io il server ci va un codice simile che faccia la stessa cosa suppongo)

Ho già fatto salire il wildlfy in modalità debug ssl, sì il mio è un war che invoca l'API REST Server di tuosito.com con Spring, eseguo il codice "non canonico" , qual è allora il codice canonico? ho googlato ma tutti i siti trovati riportano queste righe di codice:

Nel file di log sia mettendo il jks con il certificato server scaduto che quello nuovo ricevutomi ho sempre le stesse righe di log:
"ClientHello": {
"compression methods" : "00",
  "extensions"          : [
    "server_name (0)": {
      type=host_name (0), value=tuosito.com
    },
...
Consuming server Certificate handshake message (
"Certificates": [
  "certificate" : {
    "version"            : "v3",
    "serial number"      : "0X.......",
    "signature algorithm": "SHA256withRSA",
    "issuer"             : "CN=DigiCert TLS....., O=DigiCert Inc, C=US",
    "not before"         : "2022-07-06 01:00:00.000 CET",
    "not  after"         : "2023-06-30 24:59:59.000 CET",
    "subject"            : "CN=tuosito.com, ..........",
    "subject public key" : "RSA",
...
Consuming ServerHelloDone handshake message (
 <empty>
 )
...
Produced client Finished handshake message (
 "Finished": {
   "verify data": {
     0000: 25...
   }'}
 )
Consuming ChangeCipherSpec message
Consuming server Finished handshake message (
"Finished": {
  "verify data": {
    0000: 82..
  }'}
 )
Consuming HelloRequest handshake message (
 <empty>
 )
...
Consuming server Certificate handshake message (
"Certificates": [
  "certificate" : {
    "version"            : "v3",
    "serial number"      : "0X.......",
    "signature algorithm": "SHA256withRSA",
    "issuer"             : "CN=DigiCert TLS....., O=DigiCert Inc, C=US",
    "not before"         : "2022-07-06 01:00:00.000 CET",
    "not  after"         : "2023-06-30 24:59:59.000 CET",
    "subject"            : "CN=tuosito.com, ..........",
    "subject public key" : "RSA",
..
Consuming ServerHelloDone handshake message (
 <empty>
 )
Produced client Certificate handshake message (
"Certificates": [
   "certificate" : {
     "version"            : "v3",
     "serial number"      : "0A .....",
     "signature algorithm": "SHA256withRSA",
     "issuer"             : "CN=DigiCert .,
     "not before"         : "2021-06-28 02:00:00.000 CEST",
     "not  after"         : "2022-07-08 01:59:59.000 CEST",
     "subject"            : "CN=miosito.com",
     "subject public key" : "RSA",
..
Produced CertificateVerify handshake message (
 "CertificateVerify": {
   "signature algorithm": rsa_pkcs1_sha256
   "signature": {
...

Produced ChangeCipherSpec message
Produced client Finished handshake message (
 "Finished": {
   "verify data": {
     0000: E...
   }'}
 )
Consuming ChangeCipherSpec message
Consuming server Finished handshake message (
 "Finished": {
   "verify data": {
     0000: 9...
   }'}
 )

Fine, ho ricevuto tutti i dati dal server REST

Inoltre, adesso vedo la scadenza sempre 30/06/2023 sia mettendo il certificato server che è scaduto il 08/07/2022 sia quello nuovo che scadrà il giorno 30-06-2023

> 2) siccome hai il certificato del server nel client KeyStore, il client lo usa per confrontarlo con quello del server, vede che sono
identici e quindi lo trusta anche se è scaduto.


E ma hanno due scadenze diverse, torniamo la punto: quale codice Java si trusta la scadenza?

> Di solito il server certificate è firmato da una nota CA e quindi il client non ha bisogno di nulla dal server (perché nella JVM ci sono
già tutti i certificati delle CA note). 

Il server certificate nel mio Jks è sì firmato da una nota CA : DigiCert Global.... queste CA sono presenti nel mio jssecacerts (addirittura non ho neanche il cacerts nel mio server)

> Nel client c'è solo il certificato client da mandare al server per l'autenticazione e di solito questo certificato è firmato dal server
(con un altro certificato che deve avere l'estensione ca:true), più raramente il certificato del client è all'interno del keystore del
server (perché scala di meno).

non ho capito questo punto, nel client il certificato è il mio certificato con la keypair e questo cerficato non è firmato dal server (tuosito.com) ma dalla mia CA che ha emesso il mio certificato richiesto, cosa volevi dire?
A me non interessa se loro hanno il mio certificato nel loro keystore (Server provider REST tuosito), mi interessa capire come mai anche con il certificato server scaduto tuosito.com la comunicazione avviene ancora: allora che serve mettere in piedi certificati in entrambi i lati se poi manca il codice di verifica da ambo i lati...

Grazie ancora
Ciao
Beppe
Mio_jks.jpg
X509 Trust manager interface.jpg

Simone Bordet

unread,
Jul 10, 2022, 2:02:31 PM7/10/22
to Giuseppe Coniglio, JUG Torino - JVM User Group Torino
Ciao,

On Sun, Jul 10, 2022 at 6:52 PM Giuseppe Coniglio <jackf...@gmail.com> wrote:
> > "Come fai a sapere che il certificato è scaduto?"
> come ho già spiegato , apro il mio jks con Portecle/KeyStore Explorer e si vede che il certificato Server è scaduto, in allegato l'immagine esplicativa.

Quello che ti manda il server scade il 30/6/2023, ed è quello che
conta, non quelli che guardi tu da altre parti.

> Fine, ho ricevuto tutti i dati dal server REST

Ed è corretto.

> Inoltre, adesso vedo la scadenza sempre 30/06/2023 sia mettendo il certificato server che è scaduto il 08/07/2022 sia quello nuovo che scadrà il giorno 30-06-2023

Guarda, non so che dirti, ma il server ti manda un certificato valido.
E quindi la comunicazione non ha nessun problema.

> > 2) siccome hai il certificato del server nel client KeyStore, il client lo usa per confrontarlo con quello del server, vede che sono
> identici e quindi lo trusta anche se è scaduto.
>
> E ma hanno due scadenze diverse, torniamo la punto: quale codice Java si trusta la scadenza?

Non è che sia molto rilevante, è qualche classe interna del JDK e non
ci puoi fare nulla comunque.

> > Di solito il server certificate è firmato da una nota CA e quindi il client non ha bisogno di nulla dal server (perché nella JVM ci sono
> già tutti i certificati delle CA note).
>
> Il server certificate nel mio Jks è sì firmato da una nota CA : DigiCert Global.... queste CA sono presenti nel mio jssecacerts (addirittura non ho neanche il cacerts nel mio server)

Ok, allora non ti serve a niente averlo nel client KeyStore.
Toglilo che fa meno confusione.

> > Nel client c'è solo il certificato client da mandare al server per l'autenticazione e di solito questo certificato è firmato dal server
> (con un altro certificato che deve avere l'estensione ca:true), più raramente il certificato del client è all'interno del keystore del
> server (perché scala di meno).
>
> non ho capito questo punto, nel client il certificato è il mio certificato con la keypair e questo cerficato non è firmato dal server (tuosito.com) ma dalla mia CA che ha emesso il mio certificato richiesto, cosa volevi dire?
> A me non interessa se loro hanno il mio certificato nel loro keystore (Server provider REST tuosito), mi interessa capire come mai anche con il certificato server scaduto tuosito.com la comunicazione avviene ancora: allora che serve mettere in piedi certificati in entrambi i lati se poi manca il codice di verifica da ambo i lati...

Continui a insistere sul fatto che il certificato del server sia
scaduto, ma è evidente che non lo è: si vede dai DEBUG della
comunicazione.

Sul client devi solo avere un KeyStore con dentro il certificato
client da mandare al server per l'autenticazione.
Sul server devi essere in grado di validare questo certificato che
manda il client.
La soluzione che stai usando è che il server ha nel suo TrustStore il
certificato del client. Senza questo, non funzionerebbe perché il
server è configurato con "needAuth".
Di solito, invece, il certificato del client è firmato da un
certificato server (diverso da quello del dominio) per cui il server
non ha bisogno di avere il certificato del client nel suo KeyStore
(così come i clients non hanno bisogno del certificato del server).

Da quello che hai mostrato funziona tutto correttamente perché i
certificati non sono scaduti (come invece credi tu) e il server sembra
essere configurato correttamente.

Giuseppe Coniglio

unread,
Jul 10, 2022, 3:29:18 PM7/10/22
to Simone Bordet, JUG Torino - JVM User Group Torino
io sto usando un unico jks che funge sia Keystore che da Trustore

Truststore

Keystore

TrustStore memorizza le credenziali di altri.

Keystore memorizza le tue credenziali, come chiavi private o certificati di identità.

La configurazione di TrustStore è necessaria per la corretta connessione lato client.

Il Keystore è necessario quando si configura la comunicazione client-server.

Un TrustStore contiene i certificati dei sistemi esterni di cui ti fidi.

Un KeyStore contiene i certificati della tua applicazione.


Se nel mio jks tolgo il certificato pubblico Server allora a cosa serve avere tutta la teoria di avere il certificato server ?
A questo punto se dessi il mio certificato p12 ad altri anche loro invocherebbero il serzivizio REST di tuosito.com senza neanche avere il certificato server appunto, che mutua autenticazione 2 way ssl sarebbe?
image.png

> Sul server devi essere in grado di validare questo certificato che manda il client.

Quindi il soggetto B server verifica soltanto che quando qualcuno chiama li chiama (in questo caso noi miosito.com) sia trust da loro senza verificare anche la parte server, ma allora non torna quanto scrivono chi mi espone il servizio : in questo caso è la responsabilità del consumer (noi) di controllare il certificato server e fermare la comunicazione nel caso due certificati non corrispondono. La verifica del certificato server dovrebbe essere fatta dal consumer (noi)

> La soluzione che stai usando è che il server ha nel suo TrustStore il certificato del client.

Il server non lo gestisco io , ma il fornitore del servizio REST che invoco, quindi loro verificano soltanto che il chiamante siamo noi nel loro trustore ok

> Di solito, invece, il certificato del client è firmato da un certificato server (diverso da quello del dominio) per cui il server
non ha bisogno di avere il certificato del client nel suo KeyStore (così come i clients non hanno bisogno del certificato del server).

Continuo a non capire , puoi fare un esempio, il CN del certificato client è miosito.com e firmato da DIGICERT, cosa intendi?
 
Ora ho un caso inverso, io (provider) espongo un servizio REST a un soggetto client C che invocherà la mia API , anche qua uso Spring con MA ed ho replicato lo stesso caso nel jks: Quindi quando io adesso nella mia API REST esposta verso un'altro client

Anche in questo caso devo togliere il certificato ssl del client ?
image.png


> il server non ha bisogno di avere il certificato del client nel suo KeyStore (così come i clients non hanno bisogno del certificato del server).

Scusa ma allora a cosa serve che nei rapporti tra clienti e fornitori, qua a Torino sappiamo chi sono... quando un soggetto rinnova il certificato lo invia a tutti i soggetti che comunicano con lui (sia che il rapporto è provider-> consumer oppure consumer-> server) per far funzionare la Mutua autenicazione.

buona serata :-)
ciao

Simone Bordet

unread,
Jul 10, 2022, 5:53:53 PM7/10/22
to Giuseppe Coniglio, JUG Torino - JVM User Group Torino
Ciao,

On Sun, Jul 10, 2022 at 9:29 PM Giuseppe Coniglio <jackf...@gmail.com> wrote:
> Se nel mio jks tolgo il certificato pubblico Server allora a cosa serve avere tutta la teoria di avere il certificato server ?

Non so a quale teoria ti riferisci, ma non funziona come credi.
Altrimenti *ogni* browser dovrebbe avere i certificati di *tutti* i
siti del mondo e non è così.

> A questo punto se dessi il mio certificato p12 ad altri anche loro invocherebbero il serzivizio REST di tuosito.com senza neanche avere il certificato server appunto, che mutua autenticazione 2 way ssl sarebbe?
> https://www.neovasolutions.com/2020/03/19/steps-to-implement-2-way-mutual-ssl-authentication/

Mi sa che hai una grande confusione di come mutual TLS authentication
funziona. Non è come credi tu.

> Quindi il soggetto B server verifica soltanto che quando qualcuno chiama li chiama (in questo caso noi miosito.com) sia trust da loro senza verificare anche la parte server, ma allora non torna quanto scrivono chi mi espone il servizio : in questo caso è la responsabilità del consumer (noi) di controllare il certificato server e fermare la comunicazione nel caso due certificati non corrispondono. La verifica del certificato server dovrebbe essere fatta dal consumer (noi)
>

Il server è configurato con needAuth=true, quindi il client *deve*
mandare un certificato.
Quando arriva al server il certificato del client viene verificato.
O il server ce l'ha nel suo TrustStore, oppure il certificato del
client deve essere firmato da una CA nota al server.

Sul server, non c'è nessuna verifica del certificato del server.
E' il client che lo verifica.
E nel tuo caso la verifica è ok, perché il certificato del server è
ok, scadenza e CN.

> Continuo a non capire , puoi fare un esempio, il CN del certificato client è miosito.com e firmato da DIGICERT, cosa intendi?

Il CN del certificato del client è irrilevante, non viene verificato
(a meno di casi super-custom che non mi sembra essere il tuo caso).
L'unica cosa che il server verifica del certificato del client è la trust chain.
Se il server ha il client certificate nel suo TrustStore, allora è trusted.
Che sia firmato da DIGICERT e non da un certificato server è un'altra
cosa non standard, ma abbiamo capito che il tuo caso è non-standard.

> Ora ho un caso inverso, io (provider) espongo un servizio REST a un soggetto client C che invocherà la mia API , anche qua uso Spring con MA ed ho replicato lo stesso caso nel jks: Quindi quando io adesso nella mia API REST esposta verso un'altro client

Non si capisce.

> > il server non ha bisogno di avere il certificato del client nel suo KeyStore (così come i clients non hanno bisogno del certificato del server).
>
> Scusa ma allora a cosa serve che nei rapporti tra clienti e fornitori, qua a Torino sappiamo chi sono... quando un soggetto rinnova il certificato lo invia a tutti i soggetti che comunicano con lui (sia che il rapporto è provider-> consumer oppure consumer-> server) per far funzionare la Mutua autenicazione.

Questo perché il server è stato pensato così, ma non è il caso tipico.
Per carità funziona, ma il server si deve accollare un casino di
lavoro (rinnovare tutti i certificati e redistribuirli in modo sicuro
e senza sbagliarsi o confondere un client con un altro), che è un
ovvio problema di scalabilità -- va bene per 10-100, non quando ne hai
milioni.
Per fortuna PKI funziona in modo più efficiente come spiegavo nelle
email precedenti. Comunque non pensare a quest'altro caso più
efficiente.

Se nel tuo caso il server distribuisce i certificati client, cambi il
KeyStore con quello nuovo che ti dà il server e sei a posto.

Giuseppe Coniglio

unread,
Jul 10, 2022, 6:14:59 PM7/10/22
to Simone Bordet, JUG Torino - JVM User Group Torino
La mutua autenticazione o 2 ways authentication come dicono gli anglosassoni, ha nel nome il numero 2 proprio perché - indovina un po’ - il numero dei certificati usati per lo scambio è 2 (magia). Ovvero, il client ha il proprio certificato(con chiave pubblica/privata) ed il certificato pubblico del server(nei trusted) ed il Server ha il suo certificato(composto dalla chiave privata non darà a nessuno e la parte pubblica, condivisa con i client) è quello pubblico del client(nei trusted). Questa è la mutua autenticazione non si scappa.
:-) 

Simone Bordet

unread,
Jul 10, 2022, 6:48:22 PM7/10/22
to Giuseppe Coniglio, JUG Torino - JVM User Group Torino
Ciao,

On Mon, Jul 11, 2022 at 12:14 AM Giuseppe Coniglio
<jackf...@gmail.com> wrote:
>
> La mutua autenticazione o 2 ways authentication come dicono gli anglosassoni, ha nel nome il numero 2 proprio perché - indovina un po’ - il numero dei certificati usati per lo scambio è 2 (magia). Ovvero, il client ha il proprio certificato(con chiave pubblica/privata) ed il certificato pubblico del server(nei trusted) ed il Server ha il suo certificato(composto dalla chiave privata non darà a nessuno e la parte pubblica, condivisa con i client) è quello pubblico del client(nei trusted). Questa è la mutua autenticazione non si scappa.
> :-)

Guarda, lascia stare la magia con chi sta cercando di aiutarti.
E' ovvio che non hai ancora capito come funziona TLS.

Buona fortuna.
Message has been deleted

Giuseppe Coniglio

unread,
Jul 11, 2022, 7:29:44 AM7/11/22
to JUG Torino - JVM User Group Torino

Ciao Simone, ho risolto e posto il codice Java nel caso possa servire alla Community :-)

                   RestTemplate restTemplate = new RestTemplate();

                    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();

                    SSLContext sslContext = org.apache.http.ssl.SSLContextBuilder.create()
                            .loadKeyMaterial(ResourceUtils.getFile(pathFileKeystore), keyStorePassword.toCharArray(),
                                    keyPassword.toCharArray())
                            .loadTrustMaterial(ResourceUtils.getFile(pathFileKeystore), keyStorePassword.toCharArray())
                            .build();

                    CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build();
                    requestFactory.setHttpClient(client);
                    restTemplate.setRequestFactory(requestFactory);

                   String resp = restTemplate.getForObject(urlApiProvider, String.class);    



Ho fatto entrambe le prove :

1) Con il certificate server scaduto (1_cer_server_expired.jpg)

Si interrompe adesso la comunicazione con il servizio REST del server 

 "Certificates": [

   "certificate" : {

     "version"            : "v3",

     "serial number"      : "0x ------",

     "signature algorithm": "SHA256withRSA",

     "issuer"             : "CN=DigiCert T",

     "not before"         : "2021-12-21 01:00:00.000 CET",

     "not  after"         : "2023-01-22 24:59:59.000 CET",

     "subject"            : "CN=TUOSITO.com ",

     "subject public key" : "RSA",

     "extensions"         : [

       {

 

ERROR stderr  - javax.net.ssl|SEVERE|A1|Logger.java:765|Fatal (CERTIFICATE_UNKNOWN): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target (

ERROR stderr  - "throwable" : {

ERROR stderr  -   sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

 

2) Prova chiamata api rest server con il certificate server che scadrà nel 2023 (2_cer_server_expiry_2023.jpg)

Tralascio tutti i log ma la sostanza è che la chiamata arriva fino alla fine:

"Finished": {

  "verify data": {

    0000: 4E.......................................

  }'}

Ricevo i dati correttamente dal server tuosito


Buona giornata :-)


1_cer_server_expired.jpg
2_cer_server_expiry_2023.jpg

Simone Bordet

unread,
Jul 11, 2022, 10:02:35 AM7/11/22
to Giuseppe Coniglio, JUG Torino - JVM User Group Torino
On Mon, Jul 11, 2022 at 1:10 PM Giuseppe Coniglio <jackf...@gmail.com> wrote:
>
> Ciao Simone, ho risolto e posto il codice Java nel caso possa servire alla Community :-)

Per la community, la soluzione postata è evidentemente sbagliata, in
quanto dai logs è evidente che il certificato non è scaduto.

> "not before" : "2021-12-21 01:00:00.000 CET",
> "not after" : "2023-01-22 24:59:59.000 CET",

Il problema è un altro, ma tanto non vuole ascoltare neanche davanti
all'evidenza, spiega le cose con la "magia".
Non fate come postato da lui.

Giuseppe Coniglio

unread,
Jul 11, 2022, 10:34:22 AM7/11/22
to Simone Bordet, JUG Torino - JVM User Group Torino
Ciao Simone,
i test parlano chiaro ed il codice fa quello che mi serve facesse rispetto a quanto faceva prima.

1) Prova chiamata con il mio client avente il certificato server tuosito.com non presente nel mio jks oppure presente ma scaduto ho l'errore:


ERROR stderr  - javax.net.ssl|SEVERE|A1|Logger.java:765|Fatal (CERTIFICATE_UNKNOWN): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target (
ERROR stderr  -   sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
 
2) Prova chiamata con il mio client avente il certificate  server tuosito.com   che scadrà nel 2023 : Funziona la restituzione dei dati dal provider Rest

Adesso non è rilevante per me capire cosa succede dietro le quinte della JVM, di Spring oppure cosa fanno lato server, a me interessa che quando ho ricoperto i casi da gestire con il codice funzionante e  testato: se non metto un certificato valido del server la comunicazione adesso si blocca ( e quindi se la società Server non mi invia il suo certificato aggiornato la mia chiamata verso di loro si blocca e non va avanti), altrimenti ricevo tutti i dati dal server.

In 2 ways SSL client verifies the server certificates and the server verifies the client certificates. 

At the server end, there will be a Keystore which will hold the private and public certificate of the server and truststore which will hold the public certificate of client whereas, at the client end, there will be a Keystore which will hold the private and public certificate of client whereas truststore which will hold the public key of the server.

  • Clients will send Hello and request for the resources on the secure HTTPS protocol.
  • The server will respond with its public certificate (.crt) and send Hello.
  • The client will verify the server public certificate in its truststore.
  • The client sends back symmetric session key generated using the server public certificate.
  • The server will decrypt the symmetric session key using the server private certificate and request for the client certificate.
  • The client will send its public certificate to the server and the server will verify the client public certificate in the server truststore.
  • The server will generate a session key and encrypt using the client public certificate and send it to the client.
  • The client will decrypt the session key using client private certificate and this way the key exchange between client and server. It will establish secure communication between client and server.


 

2 way ssl.jpg

Giuseppe Coniglio

unread,
Jul 11, 2022, 10:40:25 AM7/11/22
to Simone Bordet, JUG Torino - JVM User Group Torino
Soluzione:
Ho risolto e posto il codice Java nel caso possa servire alla Community 🙂
RestTemplate restTemplate = new RestTemplate();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
SSLContext sslContext = org.apache.http.ssl.SSLContextBuilder.create()
.loadKeyMaterial(ResourceUtils.getFile(pathFileKeystore), keyStorePassword.toCharArray(),
keyPassword.toCharArray())
.loadTrustMaterial(ResourceUtils.getFile(pathFileKeystore), keyStorePassword.toCharArray())
.build();
CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build();
requestFactory.setHttpClient(client);
restTemplate.setRequestFactory(requestFactory);
String resp = restTemplate.getForObject(urlApiProvider, String.class);
Ho fatto entrambe le prove :
1) Con il certificate server scaduto
Si interrompe adesso la comunicazione con il servizio REST del server : PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
2) Con il il certificate server che scadrà nel 2023
Ricevo i dati correttamente dal server
1_cer_server_expired.jpg
2_cer_server_expiry_2023.jpg

Francesco Vasco

unread,
Jul 12, 2022, 2:04:07 PM7/12/22
to JUG Torino - JVM User Group Torino, Giuseppe Coniglio
Ciao Giuseppe,
permettimi una curiosità: ma nell'immagine 1_cer_server_expired.jpg che hai pubblicato come evidenza del certificato scaduto, sembra che la scadenza "05/07/2022" sia stata modificata manualmente.
Sei stato tu?
Posso chiederti come hai deciso di occultare il valore reale?
Se è un refuso, potresti pubblicare l'immagine reale?

Colgo l'occasione per chiederti se hai imbastito dei test automatici, oppure hai effettuato una verifica una tantum?

Ti chiedo un'ultima curiosità: sai per caso come si chiama il server HTTP che stai utilizzando?

Grazie in anticipo,
Vasco

--
Hai ricevuto questo messaggio perché sei iscritto al gruppo "JUG Torino - JVM User Group Torino" di Google Gruppi.
Per annullare l'iscrizione a questo gruppo e non ricevere più le sue email, invia un'email a jugtorino+...@googlegroups.com.
Per visualizzare questa discussione sul Web, visita

Giuseppe Coniglio

unread,
Jul 12, 2022, 5:59:55 PM7/12/22
to Francesco Vasco, JUG Torino - JVM User Group Torino
Ciao Francesco,
ho condiviso immagini e codice ,e per motivi di riservatezza ho forse modificato qualcosa e come puoi ben immaginare ho voluto oscurare alcuni dati ma questo non cambia la sostanza della domanda iniziale: ovvero come mai il mio codice Java che ho postato non si è accorto che il certificato server era scaduto?

Mi chiedi le immagini reali e le allego volentieri permettimi di oscurare almeno gli alias ;-)
1 Jks (trustore/keystore) certificato server con scadenza gennaio 2022
2 Jks   (trustore/keystore)  certificato server con scadenza nel 2023

Ho un war (Progetto Axis2) deployato in un Wildfly, quindi dovendo chiamare con Mutua Autenticazione il server https://tuosito.com/WSRest/Student.svc/getStudent/age=23&country=it.... ho aggiunto mesi addietro il codice seguente:


  try {
            keyStore = KeyStore.getInstance("jks");
            ClassPathResource classPathResource = new ClassPathResource("client-app.jks");
            InputStream inputStream = classPathResource.getInputStream();
            keyStore.load(inputStream, myKeyStorePassword.toCharArray());

            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(new SSLContextBuilder()
                .loadTrustMaterial(null, new TrustSelfSignedStrategy())
                .loadKeyMaterial(keyStore, myKeyPassword.toCharArray()).build(),
                NoopHostnameVerifier.INSTANCE);

            HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory)
                .setMaxConnTotal(Integer.valueOf(5))
                .setMaxConnPerRoute(Integer.valueOf(5))
                .build();

            requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
            requestFactory.setReadTimeout(Integer.valueOf(10000));
            requestFactory.setConnectTimeout(Integer.valueOf(10000));

            restTemplate.setRequestFactory(requestFactory);
        }

Googlando per ore tutti gli esempi riportavano più o meno questo codice, anche togliendo  NoopHostnameVerifier e mettendo DefaultHostnameVerifier questo codice non si accorge che la data di scadenza del certificato server nel mio jks è scaduto.

Tutto sta funzionando fino a quando non scopro quello che ho scritto nel primo post iniziale: siccome devo rinnovare
io il mio di certificato che scade a fine luglio (29/07/2022)  faccio le cose con anticipo (sempre meglio qualche settimana prima come buon senso insegna ) , al che dopo aver creato la mia CSR ed ottenuto il cer firmato dalla CA apro quindi il jks attuale e mi accorgo che il certificato server ha scadenza gennaio 2022.
Considera che dovrò inviare il mio nuovo cer (fisso la data di aggiornamento per entrambi gli attori, noi e loro, prima della  scadenza del 27/07) e chiedo anche di aver esubito dal server del servizio rest il loro certificato valido per sostituire quello che mi hanno inviato mesi fa e di cui si sono dimenticati a gennaio di inviarmi il cer aggiornato con scadenza 2023 che hanno installato nel loro server.

Quindi nel Jug quando pongo la domanda imposto la data di scadenza al 05/07/2022 del cer server al posto di gennaio 2022, ma è solo per dire che il certificato server è scaduto, è irrilevante se la data sia gennaio 2022 oppure 05/07/2022 visto che me ne sono accorto il giorno 6 luglio ....
Quindi attivo i debug ssl handshake nel wildlfy, ma quando invoco https://tuosito.com/WSRest/ nonostante nel mio jks ho il cer con scadenza 01/2022 vedo la scadenza 22-01-2023, ed anche usando un jks con soltanto il mio cer client funziona tutto , ricevo i dati correttamente e vedo sempre la scadenza del cer server 22-01-2023.


Dopo varie ricerche nel web ho risolto sostituendo il codice di prima con questo

String pathFileKeystore = " /applications/configuration/client-app.jks";

RestTemplate restTemplate = new RestTemplate();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
SSLContext sslContext = org.apache.http.ssl.SSLContextBuilder.create()
.loadKeyMaterial(ResourceUtils.getFile(pathFileKeystore), keyStorePassword.toCharArray(),
keyPassword.toCharArray())
.loadTrustMaterial(ResourceUtils.getFile(pathFileKeystore), keyStorePassword.toCharArray())
.build();
CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build();
requestFactory.setHttpClient(client);
restTemplate.setRequestFactory(requestFactory);
String resp = restTemplate.getForObject(urlApiProvider, String.class);

E' pseudo codice quindi  ovviamente non stare a guardare i valori schiantati ... è solo per far capire il codice ;-)

Deployo il nuovo war e avvio il Wildfly (il mio trustore/keystore è in una cartella del server unix /applications/configuration/client-app.jks ) 

1) Con il il certificate server che scadrà nel 2023 in  "client-app.jks"

Ricevo i dati correttamente dal server

2) Con il certificate server scaduto in  "client-app.jks"
Si interrompe adesso la comunicazione con il servizio REST del server : PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

3) Elimino il certificate server in "client-app.jks"
Si interrompe adesso la comunicazione con il servizio REST del server : PKIX path building failed:

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Ora il controllo "logico" sul certificato server funziona, perchè come ho dimostrato con le prove se fra un anno il server aggiorna il
certificato senza comunicarmelo la mia chiamata andrà in errore e quindi posso "richiedere" il nuovo certificato server da mettere
nel mio trustore  "client-app.jks"  .

Non ci sono stati test automatici, è una chiamata ad un servizio rest semplice e non c'è da metter in piedi Jenkins o altro ancora...

Spero di esser stato chiaro :-)

Ora devo creare un nuovo progetto stavolta sarà un Microservizio Spring boot di cui io sarò il fornitore con un' Api rest esposta sempre con Mutua Autenticazione. 
Ho preso spunto dai siti seguenti:

https://www.javatpoint.com/spring-boot-rest-example

 https://www.lateralecloud.it/spring-boot-servizi-web-restful/

https://www.twilio.com/blog/create-rest-apis-java-spring-boot


Ovviamente in questo caso la MA è fatta nel file application.yml :


ssl:
   client-auth: need
   #Require the Client to Identify Itself (Two-Way TLS): client-auth: need
   #The path to the keystore file. Classpath resources may also be specified, by using the classpath prefix: classpath:path/to/keystore
   key-store:  classpath:certificate/server_local.jks
   #The password of the keystore.
   key-store-password: xxxx
   #The password of the key.
   key-password:  xxxx
   key-store-type: JKS
   #The path to the truststore file. Classpath resources may also be specified, by using the classpath prefix: classpath:path/to/trust-store    
   trust-store:  classpath:certificate/server_local.jks
   #The password of the trust store
   trust-store-password: xxxx


Anche in questo come vedi dalle immagini , nel file server_local.jks.jpg io stavolta sono il server ed il file client_local.jks è quello che uso con  Soap UI  (new Rest Project) quando eseguo la chiamata rest al mio microservizio https://localhost:x98/mioserverrest..

client_local.jks va messo in Soap ui nelle preferences -> SSL Settings -> Keystore.

La mia API Rest con spring boot funziona correttamente con la MA.


Saluti 

1 certificato server con scadenza nel 2023.jpg
2 certificato server con scadenza nel 2023.jpg
server_local.jks.jpg
client_local.jks.jpg

Giuseppe Coniglio

unread,
Jul 12, 2022, 6:04:39 PM7/12/22
to Francesco Vasco, JUG Torino - JVM User Group Torino
Questa è l'immagine con il certificato server scaduto
Good night :-)
1 certificato server con scadenza gennaio 2022.jpg
Reply all
Reply to author
Forward
0 new messages