Sat­ur­day, Sep­tem­ber 5, 2009

Con­fig­ur­ing an en­crypted con­nec­tion be­tween WAS 6.1 and Or­a­cle 10g with server au­then­ti­ca­tion

I stum­bled upon some ob­sta­cles while con­fig­ur­ing a se­cured con­nec­tion be­tween Web­Sphere Ap­pli­ca­tion Server 6.​1.​0.​17 and Or­a­cle 10g Re­lease 2 over TCPS. The re­quire­ment was to es­tab­lish an en­crypted con­nec­tion with server (i.e. data­base lis­tener) au­then­ti­ca­tion. It is re­al­ized in the sec­ond sce­nario de­scribed in Or­a­cle's guide for en­abling SSL on JDBC thin dri­ver. It seems all pretty straight­for­ward and in fact it is — on the Sun's JVM the fol­low­ing code works like a charm (tested with ojdbc14.jar for Or­a­cle 10g Re­lease 2):

import java.util.Properties;
import java.sql.*;

class OracleSSLTest {
  public static void main(String[] args) throws Exception {
    DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
    String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=oracle)(PORT=2484)) (CONNECT_DATA=(SERVICE_NAME=TESTSSL)(SERVER=DEDICATED)))";
    Properties props = new Properties();
    props.setProperty("user", "testssl");
    props.setProperty("password", "testssl");
    props.setProperty("javax.net.ssl.trustStore", "client.jks");
    props.setProperty("javax.net.ssl.trustStoreType", "JKS");
    props.setProperty("javax.net.ssl.trustStorePassword", "password");

    Connection conn = DriverManager.getConnection(url, props);
    System.out.println("Great success!");
  }
}

How­ever, the same code launched on IBM JVM (build 2.3, J2RE 1.5.0 IBM J9 2.3 Linux amd64-64 j9vmx­a6423-20080315) gen­er­ates the fol­low­ing ex­cep­tion:

Exception in thread "main" java.sql.SQLException: I/O Exception: The Network Adapter could not establish the connection
  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:146)
  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:255)
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:387)
  at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:441)
  at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:165)
  at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:35)
  at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:801)
  at java.sql.DriverManager.getConnection(DriverManager.java:562)
  at java.sql.DriverManager.getConnection(DriverManager.java:155)
  at OracleSSLTest.main(Test.java:15)

I've checked that GIJ be­haves sim­i­lar. Run­ning the code with a newer JDBC dri­ver, namely ojdbc5.jar, gives more de­scrip­tive mes­sages (the im­proved ver­bosity of the new dri­vers can save you a lot of time):

Exception in thread "main" java.sql.SQLException: The Network Adapter could not establish the connection
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:412)
  at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:531)
  at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:221)
  at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
  at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:503)
  at java.sql.DriverManager.getConnection(DriverManager.java:562)
  at java.sql.DriverManager.getConnection(DriverManager.java:155)
  at OracleSSLTest.main(Test.java:15)
Caused by: oracle.net.ns.NetException: The Network Adapter could not establish the connection
  at oracle.net.nt.ConnStrategy.execute(ConnStrategy.java:359)
  at oracle.net.resolver.AddrResolution.resolveAndExecute(AddrResolution.java:422)
  at oracle.net.ns.NSProtocol.establishConnection(NSProtocol.java:672)
  at oracle.net.ns.NSProtocol.connect(NSProtocol.java:237)
  at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1042)
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:301)
  ... 7 more
Caused by: oracle.net.ns.NetException: The ssl protocol specified is not supported.
  at oracle.net.nt.TcpsConfigure.configureVersion(TcpsConfigure.java:181)
  at oracle.net.nt.TcpsNTAdapter.setSSLSocketOptions(TcpsNTAdapter.java:146)
  at oracle.net.nt.TcpsNTAdapter.connect(TcpsNTAdapter.java:121)
  at oracle.net.nt.ConnOption.connect(ConnOption.java:123)
  at oracle.net.nt.ConnStrategy.execute(ConnStrategy.java:337)
  ... 12 more
Caused by: java.lang.IllegalArgumentException: SSLv2Hello
  at com.ibm.jsse2.mb.a(mb.java:6)
  at com.ibm.jsse2.lb.<init>(lb.java:16)
  at com.ibm.jsse2.jc.setEnabledProtocols(jc.java:245)
  at oracle.net.nt.TcpsConfigure.configureVersion(TcpsConfigure.java:177)
  ... 16 more

This dif­fer­ence be­tween Sun's and IBM's JVMs is doc­u­mented. I don't want to use SSLv2 (which is con­sid­ered in­se­cure now) in any form any­way, so I added an­other prop­erty:

props.setProperty("oracle.net.ssl_version", "3.0");

En­forc­ing SSL or TSL on the lis­tener side in listener.ora doesn't do the trick. I've writ­ten some en­hanced ver­sion of the test to sim­u­late more ac­cu­rately what I be­lieve WAS is doing while es­tab­lish­ing the con­nec­tion:

import java.util.Properties;
import java.sql.*;
import javax.sql.*;
import oracle.jdbc.pool.OracleConnectionPoolDataSource;

class OracleSSLTest {
  public static void main(String[] args) throws Exception {
    DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
    String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=oracle)(PORT=2484)) (CONNECT_DATA=(SERVICE_NAME=TESTSSL)(SERVER=DEDICATED))" + 
    "(SECURITY=(SSL_SERVER_CERT_DN=\"CN=testssl,C=PL\")))";
    Properties props = new Properties();
    props.setProperty("user", "testssl");
    props.setProperty("password", "testssl");
    props.setProperty("javax.net.ssl.trustStore", "client.jks");
    props.setProperty("javax.net.ssl.trustStoreType", "JKS");
    props.setProperty("javax.net.ssl.trustStorePassword", "password");
    props.setProperty("oracle.net.ssl_server_dn_match", "true");

    props.setProperty("oracle.net.ssl_version", "3.0");
    Connection conn = DriverManager.getConnection(url, props);

    System.out.println("Great success!");

    OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
    ds.setURL(url);
    // setting username and password once again through datasource methods seems to be required as exception is thrown otherwise
    ds.setUser("testssl");
    ds.setPassword("testssl");
    ds.setConnectionProperties(props);
    PooledConnection pc = ds.getPooledConnection();

    System.out.println("Another great success!");
  }
}

Since the test run with­out an error also with ojdbc14.jar, I switched to the In­te­grated So­lu­tions Con­sole to cre­ate the data source with the above prop­er­ties. One thing to keep in mind is that the prop­er­ties to be passed to the OracleConnectionPoolDataSource fac­tory must be de­fined as a value of a newly cre­ated cus­tom prop­erty connectionProperties in the fol­low­ing form:

javax.net.ssl.trustStore=client.jks; javax.net.ssl.trustStoreType=JKS; javax.net.ssl.trustStorePassword=password; oracle.net.ssl_server_dn_match=true; oracle.net.ssl_version=3.0

An­other prob­lem one may en­counter is using an anony­mous ci­pher. Try­ing to limit ci­phers probed dur­ing the hand­shake with the state­ment:

props.setProperty("oracle.net.ssl_cipher_suites", "(SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_RC4_128_MD5, SSL_DH_anon_WITH_DES_CBC_SHA)");

Ef­fects in the fol­low­ing ex­cep­tion:

Exception in thread "main" java.sql.SQLException: I/O Exception: IBM's Client TrustManager does not allow anonymous cipher suites: SSL_DH_anon_WITH_3DES_EDE_CBC_SHA
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:421)
  at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:531)
  at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:221)
  at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
  at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:503)
  at java.sql.DriverManager.getConnection(DriverManager.java:562)
  at java.sql.DriverManager.getConnection(DriverManager.java:155)
  at OracleSSLTest.main(Test.java:15)
Caused by: javax.net.ssl.SSLHandshakeException: IBM's Client TrustManager does not allow anonymous cipher suites: SSL_DH_anon_WITH_3DES_EDE_CBC_SHA
  at com.ibm.jsse2.eb.serverHello(eb.java:199)
  at com.ibm.jsse2.eb.a(eb.java:54)
  at com.ibm.jsse2.db.m(db.java:208)
  at com.ibm.jsse2.db.a(db.java:259)
  at com.ibm.jsse2.jc.a(jc.java:271)
  at com.ibm.jsse2.jc.g(jc.java:403)
  at com.ibm.jsse2.jc.a(jc.java:401)
  at com.ibm.jsse2.j.write(j.java:10)
  at oracle.net.ns.Packet.send(Packet.java:385)
  at oracle.net.ns.ConnectPacket.send(ConnectPacket.java:173)
  at oracle.net.ns.NSProtocol.connect(NSProtocol.java:283)
  at oracle.jdbc.driver.T4CConnection.connect(T4CConnection.java:1042)
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:301)
  ... 7 more

IBM doc­u­ments a way to im­ple­ment own TrustManager and over­ride the de­fault with SSLContext.init() method for your own code, but it ob­vi­ously doesn't hit the spot. There is an­other so­lu­tion in the doc­u­men­ta­tion that sug­gests to add the line com.ibm.ssl.skipDefaultTrustManagerWhenCustomDefined=true at the top of the ssl.client.props file and de­fine the cus­tom trust man­ager with com.ibm.ssl.customKeyManager there­abouts, but it doesn't work for me.

16 com­ments:

  1. You are the man!!! I have been search­ing long and hard to find out how to do just this in a data source in WAS. thanks!

    ReplyDelete
  2. hello please i want to do this on web­sphere v7 so my ques­tion is :
    is the same pro­ce­dure as de­scribed on this ar­ti­cle use­ful for the web­sphere i want to apply it on?

    ReplyDelete
  3. @Anony­mous Un­for­tu­nately, I don't work with WAS any­more and I can­not tell if it changed in the next ver­sion.

    ReplyDelete
  4. thanks for shar­ing this ar­ti­cle to us ,it is very nice ar­ti­cle Thanks for shar­ing the de­tails!...​best re­gards.
    Linux Train­ing in Hy­der­abad

    ReplyDelete
  5. Wow, awe­some blog lay­out! How long have you been blog­ging for?
    you made blog­ging look easy. The over­all look of your
    site is mag­nif­i­cent, let alone the con­tent!

    my web page :: >> 부산오피
    (jk)

    ReplyDelete
  6. This is my first time i visit here. I found so many in­ter­est­ing stuff in your blog es­pe­cially its dis­cus­sion.
    From the tons of com­ments on your ar­ti­cles, I guess I am not the only one hav­ing all the en­joy­ment here keep up the good work

    Re­view my web­page - ..>> 안마
    (jk)

    ReplyDelete

  7. I’m not that much of a in­ter­net reader to be hon­est but your blogs re­ally nice,
    keep it up! I’ll go ahead and book­mark your site to come back in the fu­ture. Many thanks|

    Feel free to surf to my page - 오피

    (freaky)

    ReplyDelete
  8. Toto Safe Park is the pre­ferred on­line gam­ing site for Toto site users. A va­ri­ety of Toto sports and games have been re­ported live, and time money can be won de­pend­ing on the tour­na­ment. Here's a guide to rank­ing the top areas that Toto users love. 토토사이트 룰렛 안전놀이터

    ReplyDelete