Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java 5 TLS 1.2 for jdbc connection #1899

Open
abhissha opened this issue Nov 7, 2024 · 7 comments
Open

Java 5 TLS 1.2 for jdbc connection #1899

abhissha opened this issue Nov 7, 2024 · 7 comments
Labels
question Further information is requested

Comments

@abhissha
Copy link

abhissha commented Nov 7, 2024

I am trying to use Bouncy castle in Java 5 to support TLS 1.2 for JDBC connection. Based on the documentation, I can't figure out how to achieve this, since examples seems to be for Java 8 and above. Are there any working examples or documentation that I can follow to achieve my goal?

@peterdettman
Copy link
Collaborator

You can use the "BCJSSE" provider (org.bouncycastle.jsse.provider.BouncyCastleJsseProvider) in Java 5. Most JSSE features that were added in later APIs can also be accessed via BCJSSE-specific extensions.

Refer to the BCJSSE tests for examples of usage; I think there is very little dependency on Java version in those tests.

@abhissha
Copy link
Author

abhissha commented Nov 19, 2024

Based on the test cases, I tried below code and below is not working. Any help to direct in right direction would be appreciated.

I am trying to get this working on SQL JDBC driver and Java 5 based application.

The error I am getting is below:
ov 19, 2024 1:23:02 PM org.bouncycastle.jsse.provider.PropertyUtils getStringSecurityProperty
WARNING: String security property [jdk.tls.disabledAlgorithms] defaulted to: SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, ECDH
Nov 19, 2024 1:23:02 PM org.bouncycastle.jsse.provider.PropertyUtils getStringSecurityProperty
WARNING: String security property [jdk.certpath.disabledAlgorithms] defaulted to: MD2, MD5, SHA1 jdkCA & usage TLSServer, RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224, SHA1 usage SignedJAR & denyAfter 2019-01-01
Nov 19, 2024 1:23:02 PM org.bouncycastle.jsse.provider.DisabledAlgorithmConstraints create
WARNING: Ignoring unsupported entry in 'jdk.certpath.disabledAlgorithms': SHA1 jdkCA & usage TLSServer
Nov 19, 2024 1:23:02 PM org.bouncycastle.jsse.provider.DisabledAlgorithmConstraints create
WARNING: Ignoring unsupported entry in 'jdk.certpath.disabledAlgorithms': SHA1 usage SignedJAR & denyAfter 2019-01-01
Nov 19, 2024 1:23:02 PM org.bouncycastle.jsse.provider.PropertyUtils getStringSystemProperty
INFO: Found string system property [java.home]: C:\data\myinstalls\java\jdk-1.5.0_22\jre
Nov 19, 2024 1:23:02 PM org.bouncycastle.jsse.provider.PropertyUtils getStringSystemProperty
INFO: Found string system property [java.home]: C:\data\myinstalls\java\jdk-1.5.0_22\jre

com.microsoft.sqlserver.jdbc.SQLServerException: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: "unable to create JcaTlsCrypto: DEFAULT SecureRandom not available".

I tried couple of different ways: dbConnectionString is just a connection string to database.

  1. Without making any code changes, added BouncyCastleJsseProvider as a default Provider ```
    @test
    public void testDBServerWithTLSv12AsOnlyOptionUsingBouncyCastleJsseProviderDirectly() throws Exception {
    BouncyCastleJsseProvider provider = new BouncyCastleJsseProvider();
    Security.insertProviderAt(provider,1);
    // Connect to the database
    executeSQL(dbConnectionString);
    }
2. Initializing TLSv1.2 as SSL Context. Based on https://docs.oracle.com/en/java/javase/15/security/transport-layer-security-tls-protocol-overview.html#GUID-D04EF7C1-B1D4-4611-9896-A7B5573CBEED, oracle talks about TLS V1.2 works without any cert/keyexchange, so set the keymanager/trustmanager to null. I also tried below with secureRandom as null with same issue.

@test
public void testDBServerWithTLSv12AsOnlyOptionUsingBouncyCastleJsseProviderAndSSLContextWithDefaultSecureRandom() throws Exception {
BouncyCastleJsseProvider provider = new BouncyCastleJsseProvider();
Security.insertProviderAt(provider,1);
SSLContext context = SSLContext.getInstance("TLSv1.2", provider.getName());
SecureRandom secureRandom = new SecureRandom();
CryptoServicesRegistrar.setSecureRandom(secureRandom);
context.init(null,null, secureRandom);
// Connect to the database
executeSQL(dbConnectionString);
}


executeSQL is pretty straight forward method, that just calls db with a select statement

private static void executeSQL(String connectionUrl) throws Exception {
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection connection = DriverManager.getConnection(connectionUrl);
Statement statement = connection.createStatement();

        // Execute a SELECT SQL statement
        String selectSql = "SELECT Id=1";
        ResultSet resultSet = statement.executeQuery(selectSql);

        // Print results from the SELECT statement
        while (resultSet.next()) {
            System.out.println(resultSet.getString("Id"));
        }
    }
    catch(Exception e) {
        throw e;
    }
}

@peterdettman
Copy link
Collaborator

I guess there is some issue trying to create a SecureRandom of type "DEFAULT" (the exception comes from here). I guess you are not using the BouncyCastle crypto provider ("BC") i.e. BouncyCastleProvider, which should have "DEFAULT".

You could create your own subclass of JcaTlsCryptoProvider so that you can override the create(SecureRandom) method (e.g. replace SecureRandom.getInstance("DEFAULT", ...) with new SecureRandom().

Then use the BouncyCastleJsseProvider(boolean, JcaTlsCryptoProvider) constructor to create the provider instance, passing your custom JcaTlsCryptoProvider subclass.

@abhissha
Copy link
Author

Thanks for the suggestion. I tried using BouncyCastleProvider directly and as well as BouncyCastleJsseProvider. Based on your suggestion, added a new JcaTlsCryptoProvider and ran the code. Now I am running into a different issue

When I use BouncyCastleProvider-> Error is
com.microsoft.sqlserver.jdbc.SQLServerException: Reason: Login failed due to client TLS version being less than minimal TLS version allowed by the server.

at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:196)
at com.microsoft.sqlserver.jdbc.TDSTokenHandler.onEOF(tdsparser.java:246)
at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:83)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.sendLogon(SQLServerConnection.java:2532)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.logon(SQLServerConnection.java:1929)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.access$000(SQLServerConnection.java:41)
at com.microsoft.sqlserver.jdbc.SQLServerConnection$LogonCommand.doExecute(SQLServerConnection.java:1917)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:4026)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1416)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:1061)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:833)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:716)
at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:841)
at java.sql.DriverManager.getConnection(DriverManager.java:525)
at java.sql.DriverManager.getConnection(DriverManager.java:193)
at BouncyCastleProviderTest.executeSQL(BouncyCastleProviderTest.java:103)
at BouncyCastleProviderTest.testDBServerWithTLSv12AsOnlyOptionUsingBouncyCastleProviderDirectly(BouncyCastleProviderTest.java:63)
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:592)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

When I use BouncyCastleJsseProvider, error I get is below
Nov 22, 2024 10:10:20 AM org.bouncycastle.jsse.provider.PropertyUtils getStringSecurityProperty
WARNING: String security property [jdk.tls.disabledAlgorithms] defaulted to: SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, ECDH
Nov 22, 2024 10:10:20 AM org.bouncycastle.jsse.provider.PropertyUtils getStringSecurityProperty
WARNING: String security property [jdk.certpath.disabledAlgorithms] defaulted to: MD2, MD5, SHA1 jdkCA & usage TLSServer, RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224, SHA1 usage SignedJAR & denyAfter 2019-01-01
Nov 22, 2024 10:10:20 AM org.bouncycastle.jsse.provider.DisabledAlgorithmConstraints create
WARNING: Ignoring unsupported entry in 'jdk.certpath.disabledAlgorithms': SHA1 jdkCA & usage TLSServer
Nov 22, 2024 10:10:20 AM org.bouncycastle.jsse.provider.DisabledAlgorithmConstraints create
WARNING: Ignoring unsupported entry in 'jdk.certpath.disabledAlgorithms': SHA1 usage SignedJAR & denyAfter 2019-01-01

Nov 22, 2024 10:10:20 AM org.bouncycastle.jsse.provider.ProvTlsClient notifyConnectionClosed
INFO: [client #1 @18bbc5a] disconnected from [dbhostname]:1433

com.microsoft.sqlserver.jdbc.SQLServerException: The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: "No usable protocols enabled".

at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1368)
at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1412)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:1058)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:833)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:716)
at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:841)
at java.sql.DriverManager.getConnection(DriverManager.java:525)
at java.sql.DriverManager.getConnection(DriverManager.java:193)
at BouncyCastleJsseProviderTest.executeSQL(BouncyCastleJsseProviderTest.java:106)
at BouncyCastleJsseProviderTest.testDBServerWithTLSv12AsOnlyOptionUsingBouncyCastleJsseProviderDirectly(BouncyCastleJsseProviderTest.java:66)
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:592)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Caused by: java.lang.IllegalStateException: No usable protocols enabled
at org.bouncycastle.jsse.provider.ProvSSLContextSpi.getActiveProtocolVersions(Unknown Source)
at org.bouncycastle.jsse.provider.ProvTlsClient.getSupportedVersions(Unknown Source)
at org.bouncycastle.tls.AbstractTlsClient.init(Unknown Source)
at org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
at org.bouncycastle.jsse.provider.ProvSSLSocketWrap.startHandshake(Unknown Source)
at org.bouncycastle.jsse.provider.ProvSSLSocketWrap.startHandshake(Unknown Source)
at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1379)
... 31 more

I tried to run this code against Java 8 and had no issue connecting to DB using TLSv1.2. The issue seems to be specific to Java 5.

Bouncy Castle Provider Tests I am running
private BouncyCastleProvider getAndSetProvider()
{
BouncyCastleProvider provider;
provider = new BouncyCastleProvider();
Security.insertProviderAt(provider,1);

    return provider;
}

/*
    This test is by inserting BouncyCastle JSEE provider by default without any changes
 */
@Test
public void testDBServerWithTLSv12AsOnlyOptionUsingBouncyCastleProviderDirectly() throws Exception {
    getAndSetProvider();
    // Connect to the database
    executeSQL(dbConnectionString);
}

Bouncy Castle Jsse Provider Tests I am running
private BouncyCastleJsseProvider getAndSetProvider()
{
BouncyCastleJsseProvider provider;
provider = new BouncyCastleJsseProvider(false, new CustomJcaTlsCryptoProvider());
Security.insertProviderAt(provider,1);
return provider;
}

/*
    This test is by inserting BouncyCastle JSEE provider by default without any changes
 */
@Test
public void testDBServerWithTLSv12AsOnlyOptionUsingBouncyCastleJsseProviderDirectly() throws Exception {
    getAndSetProvider();
    // Connect to the database
    executeSQL(dbConnectionString);
}

@abhissha
Copy link
Author

In Java 5, on debugging further, what I found is MS SQL JDBC driver that's getting used is making below call -> SSLContext var21 = SSLContext.getInstance("SSLv3");, which is causing the BouncyCastle Provider to not pick up TLSv1.2. Since the MS SQL JDBC driver is old v2.0, is there any way in which BouncyCastle Provider can help to use TLSv1.2?

@winfriedgerlach winfriedgerlach added the question Further information is requested label Dec 13, 2024
@peterdettman
Copy link
Collaborator

@abissha Normally "jdk.tls.client.protocols" could be used to set the client protocols to support, but SSLContext.getInstance("SSLv3") will ignore that property; for historical reasons it will effectively try to use only TLSv1.

Your java.security settings apparently don't have a jdk.tls.disabledAlgorithms setting (I guess Java 1.5 hadn't introduced it yet), but the log shows we therefore default to "SSLv3, TLSv1, TLSv1.1, DTLSv1.0, (etc.)". So you can see that SSLv3, TLSv1 and TLSv1.1 will be disabled. You could try editing that property to allow TLSv1 in particular (given the getInstance call above).

I guess the server error about "minimal TLS version" is what happens when you successfully connect with TLSv1 (I assume using SunJSSE), so then TLSv1 would not be enough.

Perhaps there is a way to create the SSLContext yourself (or sometimes a way to override the SSLSocketFactory creation) and tell the JDBC driver to use yours instead of creating its own? Or is there some SSL configuration for the JDBC driver?

@SatishChoureWK
Copy link

SatishChoureWK commented Dec 18, 2024

@peterdettman I have added TLSV1.2 in my own SSLContext, and i get Exceptions.

  1. When I initialize SSLContext using this line --> sslContext.init(null,null, new SecureRandom());
    I get below exception, and i cannot create Object of SSLSocketFactory until I initialize SSLContext.

Caused by: java.lang.SecurityException: Cannot set up certs for trusted CAs
at javax.crypto.SunJCE_b.(DashoA12275)
... 34 more
Caused by: java.lang.SecurityException: Jurisdiction policy files are not signed by trusted signers!

I have the java 5 specific local_policy and US_export_policy in jre/lib/security directory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants