2012-02-15 20 views
49

Sto provando a collegarmi a un webservice sicuro.perché java non invia il certificato del client durante l'handshake SSL?

Si è verificato un errore durante l'handshake anche se il keystore e il truststore sono stati impostati correttamente.

Dopo diversi giorni di frustrazione, interminabili ricerche su google e chiedendo a tutti in giro ho scoperto che l'unico problema era che java ha scelto di non inviare il certificato client al server durante l'handshake.

In particolare:

  1. server richiesto un certificato client (CN = RootCA) - vale a dire "dammi un cert che è firmato dal CA principale"
  2. Java guardato nell'archivio chiavi e ha trovato solo il mio cliente certificato che è firmato dal "SubCA", che a sua volta è emesso dal "RootCA". Non si è preoccupato di guardare nel truststore ... duh OK immagino
  3. Purtroppo quando ho provato ad aggiungere il certificato "SubCA" al keystore, questo non mi è stato di nessun aiuto. Ho controllato se i certificati vengono caricati nel keystore. Lo fanno, ma il KeyManager ignora tutti i certificati tranne quello client.
  4. Tutti i cavi sopra al fatto che Java decide che non ha certificati che soddisfano la richiesta del server e invia niente ... tadaaa mancata stretta di mano :-(

Le mie domande:

  1. È possibile che abbia aggiunto il certificato "SubCA" al keystore in un modo che "ha rotto la catena di certificati" o qualcosa in modo che il KeyManager carichi solo il certificato client e ignori il resto? (Chrome e openssl riescono a capire perché così non può java? - nota che il certificato "SubCA" viene sempre presentato separatamente come autorità fidata così Chrome appare ntly correttamente lo comprime insieme al client cert durante l'handshake)
  2. Si tratta di un "problema di configurazione" formale sul lato server? Il server è di terze parti. Mi aspetto che il server richieda un certificato firmato dall'autorità "SubCA" poiché è ciò che ci hanno fornito. Sospetto che il fatto che funzioni in Chrome e openssl sia perché sono "meno restrittivi" e java va semplicemente "dal libro" e fallisce.

Sono riuscito a mettere insieme una soluzione sporca per questo, ma non ne sono molto contento quindi sarei felice se qualcuno può chiarire questo per me.

+2

Vale la pena aggiungere alla risposta di @ Bruno che il motivo sottostante è che c'era una chiave privata ma nessun certificato corrispondente (cioè con lo stesso alias), quindi Java non poteva inviarne uno quando veniva richiesto dai messaggi 'CertificateRequest'. Altri motivi per questo possono includere nessun certificato firmato dagli emittenti specificati dal server, oppure nessun certificato corrispondente ai codici cifrati specificati dal server. – EJP

+0

Abbiamo risolto questo problema solo facendo corrispondere le cifre specificate dal server. Grazie ragazzi per tutte queste informazioni, è stato molto utile. –

risposta

76

È possibile che sia stato importato il certificato CA intermedio nel keystore senza associarlo alla voce in cui si trova il certificato client e la chiave privata. Dovresti riuscire a vederlo usando keytool -v -list -keystore store.jks. Se si ottiene solo un certificato per voce alias, non sono insieme.

È necessario importare insieme il certificato e la relativa catena nell'alias del keystore con la chiave privata.

Per sapere quale alias dell'archivio di chiavi ha la chiave privata, utilizzare keytool -list -keystore store.jks (sto assumendo qui il tipo di archivio JKS). Questo vi dirà qualcosa di simile:

Your keystore contains 1 entry 

myalias, Feb 15, 2012, PrivateKeyEntry, 
Certificate fingerprint (MD5): xxxxxxxx 

Qui, l'alias è myalias. Se si utilizza -v oltre a questo, si dovrebbe vedere Alias Name: myalias.

Se non lo avete già separatamente, esportare il certificato client dalla chiavi:

keytool -exportcert -rfc -file clientcert.pem -keystore store.jks -alias myalias 

Questo dovrebbe dare un file PEM.

Utilizzando un editor di testo (o), preparare il file (chiamiamolo bundle.pem) con quel certificato client e il certificato CA intermedio (e possibilmente il certificato CA radice se lo si desidera), in modo che il certificato client sia all'inizio e il suo cert emittente è appena sotto.

Questo dovrebbe essere simile:

-----BEGIN CERTIFICATE----- 
MIICajCCAdOgAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJVSzEa 
.... 
-----END CERTIFICATE----- 
-----BEGIN CERTIFICATE----- 
MIICkjCCAfugAwIBAgIJAKm5bDEMxZd7MA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNV 
.... 
-----END CERTIFICATE----- 

Ora, importare questo pacchetto di nuovo insieme nella alias in cui la chiave privata è:

keytool -importcert -keystore store.jks -alias myalias -file bundle.pem 
+1

Grazie mille a Bruno - questo ha funzionato. Penso che questo potrebbe essere un po 'più documentato. Ho appena trascorso diversi giorni cercando di capire cosa diavolo sta succedendo. I suggerimenti di Java erano praticamente inesistenti. –

+1

Anche io devo combinare un certificato e una chiave privata nell'importazione, ma sto iniziando con un file di certificato * .pem (inizia con "----- BEGIN CERTIFICATE -----") e un * .key chiave privata ("----- BEGIN RSA PRIVATE KEY -----"). Ho provato a concatenarli e quindi a importare, ma ho ottenuto: keytool error: java.lang.Exception: Input non un certificato X.509. Qualche idea su dove sto andando male? Ho letto su http://stackoverflow.com/questions/5297867/ssl-tomcat-certificate-error/11984173#11984173 che potrebbe essere necessario convertire nel tipo di chiave pkcs12. Qualche idea? Sono bloccato! Grazie. –

+0

Grazie Bruno, hai salvato la mia giornata !!! – Gaucho

5

Come un add qui, è possibile utilizzare %> openssl s_client -connect host.example.com:443 e vedere il dump e controllare che tutto il cert principale sia valido contro il client. Stai cercando questo nella parte inferiore dell'output. Verifica codice di ritorno: 0 (ok)

Se si aggiunge -showcerts si scaricherà tutte le informazioni del portachiavi che è stato inviato insieme con il certificato host, che è quello che è stato caricato nel vostro portachiavi.

+0

quale comando hai usato '-showcerts'? –

+0

@JerylCook 'openssl s_client -showcerts -connect host.example.com: 443' – Sky