SSLSocketFactory, TrustManager und Apache HttpClient

zer0

Erfahrenes Mitglied
Hallo Leute!

Ich entwickle ein Programm das automatisiert Rechnungen von einem Server runterläd, sich dazu gegebenfalls einloggt. Dazu nutze ich den Apache HttpClient.

Manche Seiten benutzen selbst erstellte Zertifikate, wo durch es dann zu Problemen kam. Deswegen hab ich mir meinen eigenen TrustManager erstellt und ihn dem HTTPS Schema zugewiesen. Alles klappt wunderbar!

TrustManager der allen zertifikaten vertraut:
Java:
package com.bis.ssl;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;

public class TrustAllX509TrustManager implements X509TrustManager {

    @Override
    public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
    }

    @Override
    public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
}

SSLSocketFactory:
Java:
            SSLSocketFactory sslSocketFactory = null;
            SSLContext sslContext = SSLContext.getInstance("SSL");
            TrustManager easyTrustManager = new TrustAllX509TrustManager();
            sslContext.init(null, new TrustManager[]{easyTrustManager}, new SecureRandom());
            sslSocketFactory = new SSLSocketFactory(sslContext);

            Scheme https = new Scheme("https", 443, sslSocketFactory);
            Scheme http = new Scheme("http", 80, PlainSocketFactory.getSocketFactory());
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(http);
            schemeRegistry.register(https);

            HttpParams params = new BasicHttpParams();

            ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
            this.httpClient = new DefaultHttpClient(cm, params);

Für den Fall das man nur zertifizierte Zertifikate (die von Java aus dabei sind) annehmen darf benötige ich jetzt eine SSLSocketFactory die ich dem HTTPS Scheme zuweisen kann! Also eigentlich einfach den Java Standard für so etwas. Doch ich find einfach nichts nützliches im Internet.

Ich benutze Apache HttpClient 4.1!
 
Ich benutze die folgende Seite: https://www.swisscom-mobile.ch/ebill/servlet/AccessServlet?login&initiate&lang=de

Sollte ich die diese spezifische SocketFactory weglasen bekomme ich folgene Exception:
Code:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
        at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
        at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
        at org.apache.http.conn.ssl.SSLSocketFactory.createLayeredSocket(SSLSocketFactory.java:446)
        at org.apache.http.impl.conn.DefaultClientConnectionOperator.updateSecureConnection(DefaultClientConnectionOperator.java:200)
        at org.apache.http.impl.conn.AbstractPoolEntry.layerProtocol(AbstractPoolEntry.java:277)
        at org.apache.http.impl.conn.AbstractPooledConnAdapter.layerProtocol(AbstractPooledConnAdapter.java:142)
        at org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:758)
        at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:565)
        at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:941)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:927)

Mein Code (SSLSocketFactory auskommentiert):
Java:
            SSLSocketFactory sslSocketFactory = null;
            SSLContext sslContext = SSLContext.getInstance("SSL");
            TrustManager easyTrustManager = new TrustAllX509TrustManager();
            sslContext.init(null, new TrustManager[]{easyTrustManager}, new SecureRandom());
            sslSocketFactory = new SSLSocketFactory(sslContext);

//            Scheme https = new Scheme("https", 443, sslSocketFactory);
//            Scheme http = new Scheme("http", 80, PlainSocketFactory.getSocketFactory());
//            SchemeRegistry schemeRegistry = new SchemeRegistry();
//            schemeRegistry.register(http);
//            schemeRegistry.register(https);

            HttpParams params = new BasicHttpParams();

            //ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
            this.httpClient = new DefaultHttpClient(/*cm, */params);
 
Zuletzt bearbeitet:
Workaround:
Wir haben bei uns selbst-zertifizierte QuoVadis Zertifikate, das wird in unseren aktuellen JDK's auch nicht "erkannt". Darum "müssen" wir in die Root-CA's von QuoVadis in einen Truststore speichern.

Das geht so, indem du auf die Seite gehst, das Zertifikat runterlädtst und mit dem keytool vom SDK das CRT in den Truststore lädtst, resp. den Truststore updatest. Beim Starter der VM kann man mit vm-Parametern den Truststore angeben.

Vorteil: Es ist "sicherer" und du musst nichts Programmieren.
Nachteil: Wenn sich das Root-CA mal ändert,... geht je nachdem gar nichts mehr...

Gruss
slowy
 
Erstmal danke für den Link.
Aber da muss es doch schon eine Java Built-In Lösung geben, also ein TrustManager der allen Java Zertifikaten vertraut.

Für die selbst zertifizierten Zertifikate habe ich mein TrustManager der alle Zertifikate erlaubt und jetzt brauch ich einen der nur den Java builtin Zertifikaten vertraut.
 
Zurück