Tuesday, 20 January 2009

JDBC THIN / SSL 11g Runtime Issue - java.security.InvalidAlgorithmParameterException

I have been working on setting up JDBC THIN /SSL 11g (ojdbc6.jar) with JDK 1.6 against an 11g database. Previously I only ever done this with 10g, so here is a common runtime issue I run into while setting this up from the client side.

Runtime excepotion as follows:

java.sql.SQLRecoverableException: Io exception: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParame
terException: the trustAnchors parameter must be non-empty

Due to the fact I was using (PKCS12) wallets (ewallet.p12) I needed place Oracle PKI provider in java.security for my JDK 1.6 runtime environment as shown below.

File : D:\jdev\jdk16\jre\lib\security\java.security

security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=oracle.security.pki.OraclePKIProvider
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=sun.security.mscapi.SunMSCAPI

Once that was done the error dissapeared I was able to run my client side JDBC THIN/ SSL demo.

D:\temp\pas-ssl>java -classpath ./classes;.;D:\temp\pas-ssl\lib\ojdbc6.jar;D:\temp\pas-ssl\lib\oraclepki.jar support.au.jdbc.ssl.J
DBCSSLWalletTrustore
Start: Tue Jan 20 09:16:20 EST 2009
Conncted as DATABASE USER SCOTT
Ended: Tue Jan 20 09:16:21 EST 2009

D:\temp\pas-ssl>

So the code for this was as follows :


/*
* Author: Pas Apicella
*/

package support.au.jdbc.ssl;

import java.security.Security;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import java.util.Date;
import java.util.Properties;

import oracle.jdbc.pool.OracleDataSource;


public class JDBCSSLWalletTrustore
{
private static OracleDataSource ods = null;
private static final String TRUSTSTORE =
"D:/jdev11g-boxer/jdeveloper/jdev/mywork/JDBCSSL11g/wallets/client/ewallet.p12";
private static final String TRUSTSTORETYPE = "PKCS12";
private static final String TRUSTSTOREPASSWORD = "myclient123";
private static final String DBURL =
"jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)" +
"(HOST=beast.au.oracle.com)(PORT=2484))" +
"(CONNECT_DATA=(SERVICE_NAME=linux11g)))";

private static final String DBUSER = "scott";
private static final String DBPASSWD = "tiger";

public JDBCSSLWalletTrustore()
{
Security.addProvider(new oracle.security.pki.OraclePKIProvider());
}

public void run () throws SQLException
{
String sql = "select user from dual";
Statement stmt = null;
ResultSet rset = null;
Connection conn = null;

try
{
conn = getConnection();
stmt = conn.createStatement();
rset = stmt.executeQuery(sql);
rset.next();

if (rset != null)
{
System.out.println
(String.format("Conncted as DATABASE USER %s",
rset.getString(1)));
}
}
finally
{
if (stmt != null)
{
stmt.close();
}

if (rset != null)
{
rset.close();
}

if (conn != null)
{
conn.close();
}
}
}

public static Connection getConnection() throws SQLException
{
Properties props = new Properties();

props.setProperty("javax.net.ssl.trustStore",
TRUSTSTORE);
props.setProperty("javax.net.ssl.trustStoreType", TRUSTSTORETYPE);
props.setProperty("javax.net.ssl.trustStorePassword", TRUSTSTOREPASSWORD);

ods = new OracleDataSource();
ods.setUser(DBUSER);
ods.setPassword(DBPASSWD);
ods.setURL(DBURL);
ods.setConnectionProperties(props);

Connection conn = ods.getConnection();

return conn;
}

public static void main(String[] args)
{
System.out.println("Start: " + new Date());
JDBCSSLWalletTrustore testssl = new JDBCSSLWalletTrustore();

try
{
testssl.run();
}
catch (SQLException se)
{
System.out.println("SQL Exception occurred: ");
se.printStackTrace();
}
catch (Exception e)
{
System.out.println("Exception occurred: ");
e.printStackTrace();
}

System.out.println("Ended: " + new Date());
}


}

If you have trouble getting a JDBC THIN / SSL demo to work , it's worth tuning on this java option at run time to get more detailed information, here is what we get when we turn it on with the same code above, the output is far more detailed to enable you to debug why it may not be working for you.

-Djavax.net.debug=ssl

Output
-------

Start: Tue Jan 20 11:10:05 EST 2009
adding as trusted cert:
Subject: OU=Class 3 Public Primary Certification Authority, O="VeriSign, Inc.", C=US
Issuer: OU=Class 3 Public Primary Certification Authority, O="VeriSign, Inc.", C=US
Algorithm: RSA; Serial number: 0x70bae41d10d92934b638ca7b03ccbabf
Valid from Mon Jan 29 11:00:00 EST 1996 until Wed Aug 02 09:59:59 EST 2028

adding as trusted cert:
Subject: CN=Entrust.net Certification Authority (2048), OU=(c) 1999 Entrust.net Limited, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), O=Entrust.net
Issuer: CN=Entrust.net Certification Authority (2048), OU=(c) 1999 Entrust.net Limited, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), O=Entrust.net
Algorithm: RSA; Serial number: 0x3863b966
Valid from Sat Dec 25 04:50:51 EST 1999 until Wed Dec 25 05:20:51 EST 2019

.....

.....

*** Finished
verify_data: { 196, 181, 216, 111, 12, 62, 126, 237, 120, 137, 1, 126 }
***
main, WRITE: TLSv1 Handshake, length = 48
main, READ: TLSv1 Change Cipher Spec, length = 1
main, READ: TLSv1 Handshake, length = 48
*** Finished
verify_data: { 50, 203, 187, 227, 95, 124, 39, 44, 151, 160, 209, 59 }
***
%% Didn't cache non-resumable client session: [Session-2, TLS_RSA_WITH_AES_128_CBC_SHA]
main, WRITE: TLSv1 Application Data, length = 224
main, READ: TLSv1 Application Data, length = 48
main, WRITE: TLSv1 Application Data, length = 192
main, READ: TLSv1 Application Data, length = 160
main, WRITE: TLSv1 Application Data, length = 64
main, READ: TLSv1 Application Data, length = 208
main, WRITE: TLSv1 Application Data, length = 2080
main, WRITE: TLSv1 Application Data, length = 176
main, READ: TLSv1 Application Data, length = 2032
main, READ: TLSv1 Application Data, length = 288
main, WRITE: TLSv1 Application Data, length = 192
main, READ: TLSv1 Application Data, length = 224
main, WRITE: TLSv1 Application Data, length = 1056
main, READ: TLSv1 Application Data, length = 1360
main, WRITE: TLSv1 Application Data, length = 48
main, READ: TLSv1 Application Data, length = 208
main, WRITE: TLSv1 Application Data, length = 112
main, READ: TLSv1 Application Data, length = 512
Conncted as DATABASE USER SCOTT
main, WRITE: TLSv1 Application Data, length = 48
main, READ: TLSv1 Application Data, length = 48
main, WRITE: TLSv1 Application Data, length = 32
main, called close()
main, called closeInternal(true)
main, SEND TLSv1 ALERT: warning, description = close_notify
main, WRITE: TLSv1 Alert, length = 32
Ended: Tue Jan 20 11:10:07 EST 2009

1 comment:

Pas Apicella said...

If you don't want to edit jre.security you can enable Oracle PKI provider dynamically as shown below.

Security.insertProviderAt(new OraclePKIProvider(), 3);