2012-08-03 6 views
10

Ich versuche, eine SSL Socket-Verbindung einrichten (und auf dem Client die folgenden tue)Schwerwiegender Alarm empfangen: bad_certificate

  1. I erzeugen eine Certificte Antrag Unterzeichnung eines signierten Client-Zertifikat

  2. zu erhalten

    Jetzt habe ich einen privaten Schlüssel (verwendet während der CSR), ein signiertes Client-Zertifikat und ein Root-Zertifikat (out-of-Band erhalten).

  3. Ich füge den privaten Schlüssel und das signierte Client-Zertifikat zu einer Cert-Kette hinzu und füge das dem Schlüssel-Manager hinzu. und das Root-Zertifikat zum Trust-Manager. Aber ich bekomme einen schlechten Zertifikatfehler.

Ich bin ziemlich sicher, dass ich die richtigen Zertifikate verwende. Soll ich das signierte Client-Zertifikat auch dem Trust-Manager hinzufügen? Versuchte das, kein Glück noch.

//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); 

Gibt es eine Art Zertifikatskette, die ich hier erstellen muss?
Ich hatte auch einen P12 mit diesen Komponenten und nach der Verwendung ziemlich ähnlichen Codes, Hinzufügen des privaten Schlüssels zum Schlüsselmanager und des Stammzertifikats von P12 zum Vertrauensmanager, könnte ich es zum Funktionieren bringen. Aber jetzt muss ich es ohne den p12 arbeiten lassen.

EDIT: Stack-Trace wurde angefordert. Hoffe, das sollte ausreichen. (Anmerkung: ich die Dateinamen maskiert)

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 

Antwort

7

Sie müssen das Stammzertifikat auch zum Keystore hinzufügen.

+2

Danke nochmal. Ich habe das Client-Zertifikat und den privaten Schlüssel zum ersten Keystore (k1) hinzugefügt und dann k1 zum keymanagerfactory. Dann das root cert zu keystore (k2) und k2 zur trustmanagerfactory – highflyer

+0

Du meinst "root cert zu truststore hinzufügen", oder? – FaithReaper

1

Vorausgesetzt, dass das Server-Zertifikat signiert und gültig ist, müssen Sie nur die Verbindung wie gewohnt öffnen:

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(); 
    } 
} 

Beachten Sie, dass die URL das HTTPS-Schema hat um die Verwendung von SSL anzuzeigen.

Wenn das Zertifikat des Servers signiert ist, aber Sie den Zugriff auf einen anderen IP-Adresse/Domain-Namen als die in dem Zertifikat, können Sie den Hostnamen Überprüfung mit diesem umgehen:

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

HttpsURLConnection.setDefaultHostnameVerifier(hv); 

Wenn das Zertifikat nicht signiert Anschließend müssen Sie es zum Schlüsselspeicher hinzufügen, der von der JVM verwendet wird (useful commands).

+2

Er * ist * 'Öffnen der Verbindung wie gewohnt' und es * nicht * Arbeiten. Er verwendet kein HTTPS. Sie benötigen keinen HostnameVerifier für SSL, nur für HTTPS. Der von Ihnen gepostete ist radikal unsicher und sollte so notiert oder gar nicht gepostet werden. Keine Antwort. – EJP

1

Ich habe diesen Fehler, wenn ich diese 2 Zeilen entfernt habe. Wenn Sie wissen, dass Ihr Keystore über die richtigen Zertifikate verfügt, vergewissern Sie sich, dass Ihr Code den richtigen Keystore anzeigt.

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

ich auch dieses VM Argument benötigt: -Djavax.net.ssl.trustStore=/app/certs/keystore.jk Sehen Sie hier für weitere Informationen: https://stackoverflow.com/a/34311797/1308453

Verwandte Themen