# SSLSocketFactory, TrustManager und Apache HttpClient



## zer0 (8. September 2011)

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:

```
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:

```
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!


----------



## Thomas Darimont (13. September 2011)

Hallo,

hast du vielleicht eine Beispielseite parat mit dem man solch eine SSLSocketFactory testen kann.

Gruß Tom


----------



## zer0 (13. September 2011)

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:

```
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):

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


----------



## SE (13. September 2011)

Dein Link ist fehlerhaft ...
Deiner enthält ein HTML-Sonderzeichen "&amp;" ... was die Kodierung für das Zeichen "&" ist.
Das das natürlich keine gültige URL ist erübrigt sich zu sagen.
Die richtige URL müsste so lauten :
https://www.swisscom-mobile.ch/ebill/servlet/AccessServlet?login&initiate&lang=de


----------



## zer0 (14. September 2011)

Das werd ich schnell abändern! Wobei der Link bei mir trotzdem funktioniert!


----------



## slowfly (15. September 2011)

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


----------



## Thomas Darimont (15. September 2011)

Hallo,


hier:
http://www.exampledepot.com/egs/java.security.cert/ListTrustAnchors.html
wird gezeigt wie man alle Standardmäßig vertrauten Root CAs im JDK auflistet.
Eventuell kannst du daraus die gewünschten X509-Zertifkate in deinem eigenen TrustManager verwenden.

Gruß Tom


----------



## zer0 (16. September 2011)

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.


----------

