Intelligente Lösungen
in neuer Dimension

DB2: Probleme mit SSL-Verbindungen und Java7

Viele unserer Kunden setzen DB2 als Datenbank ein. DB2 kann JDBC-Verbindungen mittels TLS verschlüsseln. Leider treten dabei gelegentlich Probleme auf, die “Anwender” melden dann idR. Zertifikatsprobleme unabhängig vom tatsächlichen Problem.

Ausgangslage

Zugriff auf die DB2 klappt für alle Programme, die Java8 oder neuer verwenden. Bei Java7 gibt es eine “SSLHandshakeException”:

1
2
3
4
5
6
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
  at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
  at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
  at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1991)
  at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1098)
...

Oberflächlich ist klar:

  • Entweder ist das DB2-Zertifikat abgelaufen
  • … oder von einer merkwürdigen CA ausgestellt
  • … oder die CA nicht im “cacerts” eingetragen (das ist “was spezielles” für diesen Kunden, er ändert diese gerne)

Analyse DB2-Zertifikat

Sichtung des Zertifikats mit OPENSSL:

1
2
3
$ openssl s_client -connect db2.internal.biz:62000
CONNECTED(00000003)
13795:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:s23_clnt.c:610:

… scheint nicht zu klappen. Liegt an der veralteten Version von OPENSSL:

1
2
$ openssl version
OpenSSL 0.9.8j-fips 07 Jan 2009

Neuer Versuch mit neuerer Version:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ openssl version
OpenSSL 1.0.1g 7 Apr 2014
$ openssl s_client -connect db2.internal.biz:62000
CONNECTED(00000003)
depth=2 DC = biz, DC = ios, DC = iosPKI, CN = IOS-CA-ROOT-42
verify return:1
depth=1 DC = biz, DC = ios, DC = iosPKI, CN = IOS-CA-PROC-43
verify return:1
depth=0 C = DE, O = IOS GmbH, OU = DB2ADM, CN = db2.internal.biz, L = Stuttgart, ST = Baden-Wuerttemberg
...
$ openssl s_client -connect db2.internal.biz:62000|openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 3899571 (0x3b80b3)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: DC=biz, DC=ios, DC=iosPKI, CN=IOS-CA-PROC-43
        Validity
            Not Before: Mar 22 12:17:19 2019 GMT
            Not After : Mar 22 00:00:00 2023 GMT
        Subject: C=DE, O=IOS GmbH, OU=DB2ADM, CN=db2.internal.biz, L=Stuttgart, ST=Baden-Wuerttemberg
...
            X509v3 Subject Alternative Name: 
                DNS:gateway001.internal.biz, DNS:gateway002.internal.biz
...

Man sieht: * das Zertifikat ist gültig * … und von der richtigen CA ausgestellt * … und auf die richtigen Namen ausgestellt

Am Zertifikat gibt es nichts zu bemängeln!

Abstimmung mit dem DB2-Team – Ciphers

Das DB2-Team hat die BSI-Empfehlung zu TLS umgesetzt und die darin enthaltenen Ciphers als zulässig konfiguriert.

Also Quercheck mit unserer Java7-Version: Gibt es da Überlappungen? Unterstützt unsere Java7-Version einen der hinterlegten Ciphers? Die unterstützten Ciphers kann man sich leicht anzeigen lassen mit Ciphers.java:

1
2
3
4
5
6
7
8
9
10
11
12
$ javac Ciphers.java
$ java Ciphers
Default   Cipher
  SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
* SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
  SSL_DHE_DSS_WITH_DES_CBC_SHA
...
* TLS_RSA_WITH_AES_128_CBC_SHA
* TLS_RSA_WITH_AES_128_CBC_SHA256
* TLS_RSA_WITH_AES_256_CBC_SHA
* TLS_RSA_WITH_AES_256_CBC_SHA256
  TLS_RSA_WITH_NULL_SHA256

Das “Sternchen” bedeutet hier, dass es sich um einen “Default Cipher” handelt. Es gibt beispielsweise den Cipher TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, der in der Liste der Default Ciphers enthalten ist und auch in der BSI-Liste. “Eigentlich müßte es funktionieren”.

Analyse mit SSLPoke

Mit SSLPoke kann man weitere Erkenntnisse sammeln:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ javac SSLPoke.java
$ /java8/bin/java SSLPoke db2.internal.biz 62000
Successfully connected
$ java SSLPoke db2.internal.biz 62000
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
  at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
  at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
  at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1991)
  at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1098)
  at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1344)
  at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:721)
  at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)
  at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:136)
  at SSLPoke.main(SSLPoke.java:31)

SSLPoke verhält sich ähnlich zu den Java-Programmen: Mit Java8 funktioniert alles, mit Java7 gibt’s Probleme!

Also: SSL-Debugging aktivieren und nochmal probieren:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ java -Djavax.net.debug=all SSLPoke db2.internal.biz 62000
keyStore is : 
keyStore type is : jks
keyStore provider is : 
init keystore
...
trigger seeding of SecureRandom
done seeding SecureRandom
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256
Allow unsafe renegotiation: false
Allow legacy hello messages: true
...

Viele Ciphers werden also ignoriert! Das sind insbesondere alle, die in der Cipher-Liste vom DB2-Team enthalten sind.

Es stellt sich heraus, dass Java7 per Default kein TLSv1.2 aktiviert und die Ciphers sind nur für TLSv1.2 oder neuer zulässig!

Lösung

Die Lösung des Problems sieht für uns so aus, dass wir TLSv1.2 für die JavaVM aktivieren.

Test mit SSLPoke:

1
2
$ java -Djdk.tls.client.protocols=TLSv1.1,TLSv1.2 SSLPoke db2.internal.biz 62000
Successfully connected

Sieht gut aus!

Wir bauen den Parameter -Djdk.tls.client.protocols=TLSv1.1,TLSv1.2 auch in die Start-Skripte von unseren Tomcats ein und damit ist das Thema erledigt.

Links