Guten Tag,
ich habe hier einen Server, der nur sichere Verbindungen mit Client-Zertifikat zulässt. Dieses ist zudem selbst signiert. Mein Vorgehen bislang ist wie folgt (Java 6):
Ich habe ein PEM-File mit dem Private Key. Daraus habe ich einen Java-Keystore im JKS-Format erstellt:
Mit -list kann ich mir den Eintrag auch toll anzeigen lassen, also scheint zumindest die Erstellung schonmal zu funktionieren.
Dann bin ich auf diese Seite, habe das dort vorhandene Programm InstallCert angepasst und einen Truststore erzeugt (den habe ich, wie das wohl meist geschieht, cacerts genannt).
So. Nun also das ganze mal ausprobieren. Erstmal schaue ich mit einem SSLSocket, ob der Truststore funktioniert:
Das funktioniert (mit einem HandshakeCompletedListener sieht man das auch, wollte den Code nur kurz halten). Dass mein Truststore funktioniert sehe ich auch daran, dass wenn die Properties nicht gesetzt sind, entsprechende Exceptions fliegen (wie in oben verlinktem Blogeintrag).
Jetzt versuche ich aber z. B. auf den Webserver zuzugreifen, zu welchem ich ja nur per Client-Zertifikat komme. Das klappt nicht:
Dabei erhalte ich diese schöne Exception (erscheint in Zeile 10 in obigem Listing):
Dabei ist es irrelevant, ob ich das Client-Zertifikat einfüge, oder nicht. Die Passwörter der Keystores stimmen; jedenfalls funktionieren sie bei einem "keytool -list". Der Pfad zu der Datei stimmt auch, weil per Firefox und importiertem Zertifikat (dort hat es natürlich nicht das proprietäre JKS-Format, sondern PKCS#11) klappt es.
Irgendetwas habe ich wohl noch falsch. Meine Frage natürlich nun: Was könnte das sein? Ich habe irgendwie das Gefühl, dass der private Schlüssel aus dem .pem-File nicht in den Keystore übertragen wird, aber ich kann mir nach viel Googelei nicht so recht erklären, wie es anders gemacht werden könnte.
ich habe hier einen Server, der nur sichere Verbindungen mit Client-Zertifikat zulässt. Dieses ist zudem selbst signiert. Mein Vorgehen bislang ist wie folgt (Java 6):
Ich habe ein PEM-File mit dem Private Key. Daraus habe ich einen Java-Keystore im JKS-Format erstellt:
Code:
keytool -import -keystore keystore.jks -file mein_keyfile.pem
Dann bin ich auf diese Seite, habe das dort vorhandene Programm InstallCert angepasst und einen Truststore erzeugt (den habe ich, wie das wohl meist geschieht, cacerts genannt).
So. Nun also das ganze mal ausprobieren. Erstmal schaue ich mit einem SSLSocket, ob der Truststore funktioniert:
Java:
System.setProperty("javax.net.ssl.trustStore", "pfad/zum/cacerts");
System.setProperty("javax.net.ssl.trustStorePassword", "mein_password");
SSLContext ctxt = SSLContext.getDefault();
SSLSocketFactory ssf = ctxt.getSocketFactory();
SSLSocket socket = (SSLSocket) ssf.createSocket("rechnername", 443);
socket.startHandshake();
socket.close();
Jetzt versuche ich aber z. B. auf den Webserver zuzugreifen, zu welchem ich ja nur per Client-Zertifikat komme. Das klappt nicht:
Java:
System.setProperty("javax.net.ssl.keyStore", "pfad/zum/keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "mein_password");
System.setProperty("javax.net.ssl.trustStore", "pfad/zum/cacerts");
System.setProperty("javax.net.ssl.trustStorePassword", "mein_password");
url = new URL("https://hostname/pfad/zu/einer/existierenden/datei");
URLConnection urlc = url.openConnection();
InputStream is = urlc.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
Code:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
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:1657)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:932)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:746)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:75)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:258)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:687)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:632)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:652)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1000)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at client.Cert.main(Cert.java:47)
Irgendetwas habe ich wohl noch falsch. Meine Frage natürlich nun: Was könnte das sein? Ich habe irgendwie das Gefühl, dass der private Schlüssel aus dem .pem-File nicht in den Keystore übertragen wird, aber ich kann mir nach viel Googelei nicht so recht erklären, wie es anders gemacht werden könnte.