# SSL-Verschlüsselung



## Keo (21. Apr 2010)

Bei meinem Kunden steht ein Web Service, der über eine SSL-Verbindung verschlüsselt ist. Ich habe nun die Aufgabe per Webservice-Client auf diesen verschlüsselten Web Service zuzugreifen. Ein X.509 Zertifikat für diese SSL-Verbindung wurde vom Kunden ausgestellt.

Hierzu habe ich folgende Fragen:

1. Angeblich benötigt der Client kein Zertifikat um eine SSL-Verbindung aufzubauen. Der Kunde hat es mit SoapUI ausprobiert und es funktioniert auch ohne die Einbindung des Zertifikats. Ist das überhaupt möglich? - Wie soll denn dann eine Ver-/Entschlüsselung funktionieren?

2. Ich möchte gerne das Szenario zuhause testen, indem ich selbst einen Test-Webservice im Tomcat baue. Im conf/server.xml wird folgender Eintrag gemacht:

[XML]<Connector 
           port="8443" minSpareThreads="5" maxSpareThreads="75"
           enableLookups="true" disableUploadTimeout="true" 
           acceptCount="100"  maxThreads="200"
           scheme="https" secure="true" SSLEnabled="true"
           keystoreFile="security/service.cer"
           clientAuth="false" sslProtocol="TLS"/>[/XML]

Ich bekomme hierzu folgende Fehlermeldung:

```
java.io.IOException: Invalid keystore format
        at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:632)
```
Beim KeystoreFile habe ich einfach das Zertifikat übergeben. Muss ich zu dem Zertifiat noch irgenwie ein Keystore erstellen?


----------



## Murray (21. Apr 2010)

Keo hat gesagt.:


> Muss ich zu dem Zertifiat noch irgenwie ein Keystore erstellen?


Richtig, du must einen Keystore erstellen und das Zertifikat in diesen Keystore importieren. Details findest in der Doku zu keytool.exe.


----------



## Keo (30. Apr 2010)

mitlerweile habe ich vom Kunden einen Keystore(.jks) bekommen. Um diesen Keystore in den Client einzubinden, musst man eigentlich nur noch die Properties setzen:


```
System.setProperty("javax.net.ssl.trustStore", trustStoreFile);
System.setProperty("javax.net.ssl.keyStorePassword", "changeit");
```

Wie wird eigentlich der trustStoreFile von JSSE eingelesen? Ich habe sowohl einen dynamischen Dateipfad als auch einen absoluten Dateipfad übergeben und bekomme dauernd die folgende Fehlermdldung:


```
Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
	at java.security.cert.PKIXParameters.setTrustAnchors(PKIXParameters.java:183)
	at java.security.cert.PKIXParameters.<init>(PKIXParameters.java:103)
	at java.security.cert.PKIXBuilderParameters.<init>(PKIXBuilderParameters.java:87)
	at sun.security.validator.PKIXValidator.<init>(PKIXValidator.java:57)
```

Ich habe auch versucht, den Keystore in eine Jar einzubinden und die Property wie folgt gesetzt:


```
String s = getClass().getResource("client.jks").toString();
		System.setProperty("javax.net.ssl.trustStore",s);
```

Das hat leider auch nicht funktioniert. Bei mir läuft dieser Webservice-Client auf einem JBOSS. Es wäre also ganz gut, wenn ich den Keystore aus einer Jar einlesen kann.

Kann mir jmd. weiter helfen?


----------



## nixnick (30. Apr 2010)

> Ich habe auch versucht, den Keystore in eine Jar einzubinden und die Property wie folgt gesetzt:
> 
> 
> ```
> ...



bist du sicher, dass getResource() bei dir auch nicht null zurückgibt?
wie ich hier http://www.java-forum.org/deployment/99580-ausfuehrbare-dateien-jar-dateien-verwenden.html vorhin schon geschrieben habe, gibt es bei mir bisher NUR null zurück, und ich habe keinen schimmer, wieso.


----------



## Keo (30. Apr 2010)

Mit dem folgenden Code bekomme ich auch den richtigen Dateipfad zurück.

```
String s = getClass().getResource("client.jks").toString();
```

Daran kannst also nicht liegen.


----------



## nixnick (30. Apr 2010)

funktioniert das auch, wenn die resource in einem jar-archiv liegt?
bei mir tut es das nicht...


----------



## Guest2 (30. Apr 2010)

Moin,

grundsätzlich brauchst Du auf dem Server einen Java KeyStore in dem sich der private Schlüsselteil und das öffentliche Zertifikat des Servers befindet. Dieses öffentliche Zertifikat kann selbstsigniert sein (also mit dem eigenen privaten Schlüsselteil signiert), sollte aber besser von einer übergeordneten Zertifizierungsstelle ausgestellt sein (das kann auch eine hausinterne CA sein, die ihrerseits wiederum nur einen selbstsignierten Schlüssel verwendet).
(Wenn eine CA verwendet wird, so muss das Zertifikat dieser in den TrustStore des Servers)

Auf der Clientseite brauchst Du für die Verschlüsselung keinerlei Zertifikate! Allerdings kann der Client dann auch nicht die Authentizität des Servers prüfen, dies bedeutet, es kann nicht garantiert werden, das der Client sich mit einem gültigen Server verbunden hat. Um dies zu können sollte der Client das öffentliche Zertifikat der übergeordneten CA kennen, um dann das vom Server verwendete Zertifikat validieren zu können. Dazu muss das öffentliche Zertifikat der CA in den Java TrustStore (wenn der Server ein selbstsigniertes Zertifikat nutzt, dann muss dieses in den TrustStore).

Auf der Clientseite wird nur ein Java KeyStore benötigt, wenn sich der Client gegen den Server Authentifizieren soll. Wenn der Kunde Dir einen KeyStore gegeben hat, solltest Du prüfen ob in diesem der private Schlüsselteil des Servers vorhanden ist, falls ja darf dieser KeyStore niemals an die Clients ausgeliefert werden (dies würde die Verschlüsselung praktisch ad absurdum führen).

Da Du einen TrustStore nicht direkt aus einem JAR heraus laden kannst, würde ich im JAR des Clients lediglich das öffentliche Zertifikat der übergeordneten CA (bzw. das selbstsignierte Zertifikat des Servers) ablegen (als cer) und den TrustManager überschreiben. Dieser kann dann das Zertifikat direkt aus dem JAR laden und die Verbindung dagegen prüfen.

Gruß,
Fancy


----------



## Keo (3. Mai 2010)

Den Fehler, dass der Keystore nicht gefunden wurde, habe ich nun gelöst. Man sollte grundsätzlich prüfen, ob im System-Propterty die Keystores bereits angelegt wurden.


```
Properties systemProps = System.getProperties();

		while( systemProps.containsKey( "javax.net.ssl.trustStore" ) ){
			systemProps.remove( "javax.net.ssl.trustStore" );
			systemProps.remove( "javax.net.ssl.trustStorePassword" );
		}

		systemProps
			.put( "javax.net.ssl.trustStore", "client.jks" );
		systemProps.put( "javax.net.ssl.trustStorePassword", "changeit" );
		systemProps.put( "javax.net.debug", "ALL" );

		System.setProperties( systemProps );
```

Soweit funktioniert es nun auf Windows. Aber kaum habe ich das System auf ein Solaris installiert, knallt es:


```
19:12:09,336 INFO  [HttpMethodDirector] I/O exception (java.net.SocketException) caught when processing request: Unconnected sockets not implemented
19:12:09,336 INFO  [HttpMethodDirector] Retrying request
19:12:09,337 INFO  [HttpMethodDirector] I/O exception (java.net.SocketException) caught when processing request: Unconnected sockets not implemented
19:12:09,337 INFO  [HttpMethodDirector] Retrying request
19:12:09,337 INFO  [HttpMethodDirector] I/O exception (java.net.SocketException) caught when processing request: Unconnected sockets not implemented
19:12:09,337 INFO  [HttpMethodDirector] Retrying request
19:12:09,337 INFO  [HTTPSender] Unable to sendViaPost to url[[url]https://localhost:8443/axis2/services/Service?wsdl][/url]
java.net.SocketException: Unconnected sockets not implemented
        at javax.net.SocketFactory.createSocket(SocketFactory.java:97)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:115)
        at org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory.createSocket(SSLProtocolSocketFactory.java:129)
        at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:706)
```

Hat jmd. ein ähnliches Problem gehabt?


----------

