2012-08-03 5 views
10

Sto provando ad installare una connessione SSL Socket (e sto facendo il seguente sul client)Ricevuto avviso fatale: bad_certificate

  1. ho generare un Certificte richiesta di firma per ottenere un certificato client firmato

  2. Ora ho una chiave privata (utilizzata durante la CSR), un certificato client firmato e un certificato radice (ottenuto fuori banda).

  3. Aggiungo la chiave privata e il certificato client firmato a una catena di certificati e la aggiungo al gestore delle chiavi. e il certificato di root per il gestore di fiducia. Ma ottengo un errore di certificato errato.

Sono sicuro che sto usando i certificati giusti. Devo aggiungere anche il certificato cliente firmato al gestore di fiducia? Ho provato questo, senza fortuna ancora.

//I add the private key and the client cert to KeyStore ks 
FileInputStream certificateStream = new FileInputStream(clientCertFile); 
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); 
java.security.cert.Certificate[] chain = {}; 
chain = certificateFactory.generateCertificates(certificateStream).toArray(chain); 
certificateStream.close(); 
String privateKeyEntryPassword = "123"; 
ks.setEntry("abc", new KeyStore.PrivateKeyEntry(privateKey, chain), 
     new KeyStore.PasswordProtection(privateKeyEntryPassword.toCharArray())); 

//Add the root certificate to keystore jks 
FileInputStream is = new FileInputStream(new File(filename)); 
CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
java.security.cert.X509Certificate cert = (X509Certificate) cf.generateCertificate(is); 
System.out.println("Certificate Information: "); 
System.out.println(cert.getSubjectDN().toString()); 
jks.setCertificateEntry(cert.getSubjectDN().toString(), cert); 

//Initialize the keymanager and trustmanager and add them to the SSL context 
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 
kmf.init(ks, "123".toCharArray()); 
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 
tmf.init(jks); 

C'è una sorta di catena di certificati che ho bisogno di creare qui?
Avevo un p12 anche con questi componenti e dopo aver usato codice abbastanza simile, aggiungendo la chiave privata al keymanager e il cert root da p12 al gestore di fiducia, potevo farlo funzionare. Ma ora ho bisogno di farlo funzionare senza la p12.

MODIFICA: è stata richiesta la traccia di stack. Spero che questo dovrebbe essere sufficiente. (NOTA: I mascherato i nomi dei file)

Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate 
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) 
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1720) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:954) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149) 
at client.abc2.openSocketConnection(abc2.java:33) 
at client.abc1.runClient(abc1.java:63) 
at screens.app.abc.validateLogin(abc.java:197) 
... 32 more 

risposta

7

È necessario aggiungere anche il certificato radice al keystore.

+2

Grazie ancora. Ho aggiunto il certificato cliente e la chiave privata al primo keystore (k1) e poi k1 al keymanagerfactory. Quindi il certificato radice a keystore (k2) e k2 a trustmanagerfactory – highflyer

+0

Vuoi dire "aggiungi cert root a truststore", giusto? – FaithReaper

1

A condizione che il certificato del server è firmato e valido, è sufficiente aprire la connessione come al solito:

import java.net.*; 
import java.io.*; 

public class URLConnectionReader { 
    public static void main(String[] args) throws Exception { 
     URL google = new URL("https://www.google.com/"); 
     URLConnection yc = google.openConnection(); 
     BufferedReader in = new BufferedReader(new InputStreamReader(
            yc.getInputStream())); 
     String inputLine; 
     while ((inputLine = in.readLine()) != null) 
      System.out.println(inputLine); 
     in.close(); 
    } 
} 

Nota che l'URL ha lo schema HTTPS per indicare l'uso di SSL.

Se il certificato del server è firmato, ma si accede utilizzando un diverso indirizzo IP/nome del dominio rispetto a quello nel certificato, è possibile ignorare la verifica hostname con questo:

HostnameVerifier hv = new HostnameVerifier() { 
    public boolean verify(String urlHostName,SSLSession session) { 
     return true; 
    } 
}; 

HttpsURLConnection.setDefaultHostnameVerifier(hv); 

Se il certificato non è firmato quindi è necessario aggiungerlo al keystore utilizzato da JVM (useful commands).

+2

Egli * è * 'apertura della connessione, come al solito' e * non è * di lavoro. Non sta usando HTTPS. Non hai bisogno di un nomehostVerificatore per SSL, solo per HTTPS. Quello che hai pubblicato è radicalmente insicuro e dovrebbe essere notato, o non pubblicato affatto. Non una risposta – EJP

1

Ho ricevuto questo errore quando ho rimosso queste 2 righe. Se sai che il tuo keystore ha i certs giusti, assicurati che il tuo codice guardi il keystore giusto.

System.setProperty("javax.net.ssl.keyStore", <keystorePath>)); 
System.setProperty("javax.net.ssl.keyStorePassword",<keystorePassword>)); 

Ho anche bisogno di questo argomento VM: -Djavax.net.ssl.trustStore=/app/certs/keystore.jk Vedi qui per maggiori dettagli: https://stackoverflow.com/a/34311797/1308453