"Algorithm ECDH not available" using bcprov & bctls on JRockit 6

1.9k Views Asked by At

I'm trying to authorize an old JBoss 5 running on JRockit 6 to access to a CAS server using a Let's encrypt certificate.

The problem is that Let's encrypt is not supported on JDK6 so I added the root certificate to the cacerts file.

Now the problem is that JDK 6 does not understand such big key (java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)) so I tried to switch to Bouncy Castle JCE/JCA by adding bcprov-jdk15on-1.61.jar & bctls-jdk15on-1.61.jar to the $JAVA_HOME/jre/lib/ext folder & added org.bouncycastle.jce.provider.BouncyCastleProvider & org.bouncycastle.jsse.provider.BouncyCastleJsseProvider as first security providers in $JAVA_HOME/jre/lib/security/java.security file as explained partly here.

After a java.lang.ArrayIndexOutOfBoundsException: 64 I switched from SunX509 to X.509 value for ssl.KeyManagerFactory.algorithm key in java.security file.

Now I have the following error (I think the same as this thread on Oracle forum):

java.security.NoSuchAlgorithmException: Algorithm ECDH not available
  javax.crypto.KeyAgreement.getInstance(DashoA13*..)
  org.bouncycastle.jcajce.util.DefaultJcaJceHelper.createKeyAgreement(Unknown Source)
  org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.calculateKeyAgreement(Unknown Source)
  org.bouncycastle.tls.crypto.impl.jcajce.JceTlsECDomain.calculateECDHAgreement(Unknown Source)
  org.bouncycastle.tls.crypto.impl.jcajce.JceTlsECDH.calculateSecret(Unknown Source)
  org.bouncycastle.tls.TlsECDHEKeyExchange.generatePreMasterSecret(Unknown Source)
  org.bouncycastle.tls.TlsProtocol.establishMasterSecret(Unknown Source)
  org.bouncycastle.tls.TlsClientProtocol.handleHandshakeMessage(Unknown Source)
  org.bouncycastle.tls.TlsProtocol.processHandshakeQueue(Unknown Source)
  org.bouncycastle.tls.TlsProtocol.processRecord(Unknown Source)
  org.bouncycastle.tls.RecordStream.readRecord(Unknown Source)
  org.bouncycastle.tls.TlsProtocol.safeReadRecord(Unknown Source)
  org.bouncycastle.tls.TlsProtocol.blockForHandshake(Unknown Source)
  org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
  org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
  org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
  sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
  sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:167)
  sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1031)
  sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
  org.jasig.cas.client.validation.Saml11TicketValidator.retrieveResponseFromServer(Saml11TicketValidator.java:216)

But by looking at org.bouncycastle.jcajce.provider.asymmetric.EC's sources such KeyAgreement should be correctly set by org.bouncycastle.jce.provider.BouncyCastleProvider.

But effectively, as it is the org.bouncycastle.jsse.provider.BouncyCastleJsseProvider which is used when creating a https client, this provider doesn't register this algorithm and I don't know how to do this.

Someone knows how to workaround this?

I have also tried to declare those jars as dependencies to my war and explicitely instanciate them like this:

    static {
            org.bouncycastle.jce.provider.BouncyCastleProvider bcp = new org.bouncycastle.jce.provider.BouncyCastleProvider();
            java.security.Security.insertProviderAt(bcp, 1);
            org.bouncycastle.jsse.provider.BouncyCastleJsseProvider bcjp = new org.bouncycastle.jsse.provider.BouncyCastleJsseProvider(bcp);
            java.security.Security.insertProviderAt(bcjp, 1);
    }

But then, I have this stack that seems to be linked to a problem in JBoss:

java.lang.SecurityException: JCE cannot authenticate the provider BC
    javax.crypto.Cipher.getInstance(DashoA13*..)
    org.bouncycastle.jcajce.util.ProviderJcaJceHelper.createCipher(Unknown Source)
    org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.hasEncryptionAlgorithm(Unknown Source)
    org.bouncycastle.tls.TlsUtils.isSupportedCipherSuite(Unknown Source)
    org.bouncycastle.tls.TlsUtils.getSupportedCipherSuites(Unknown Source)
    org.bouncycastle.jsse.provider.ProvTlsClient.getSupportedCipherSuites(Unknown Source)
    org.bouncycastle.tls.AbstractTlsClient.init(Unknown Source)
    org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
    org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
    org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
    sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
    sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:167)
    sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1031)
    sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
    org.jasig.cas.client.validation.Saml11TicketValidator.retrieveResponseFromServer(Saml11TicketValidator.java:216)
Caused by: java.util.jar.JarException: Cannot parse jar:file:/opt/jboss-5.1.0.GA/server/default/deploy/myapp.war/WEB-INF/lib/bcprov-jdk15on-1.61.jar!/
    javax.crypto.SunJCE_c.a(DashoA13*..)
    javax.crypto.SunJCE_b.b(DashoA13*..)
    javax.crypto.SunJCE_b.a(DashoA13*..)
    javax.crypto.Cipher.getInstance(DashoA13*..)
    org.bouncycastle.jcajce.util.ProviderJcaJceHelper.createCipher(Unknown Source)
    org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.hasEncryptionAlgorithm(Unknown Source)
    org.bouncycastle.tls.TlsUtils.isSupportedCipherSuite(Unknown Source)
    org.bouncycastle.tls.TlsUtils.getSupportedCipherSuites(Unknown Source)
    org.bouncycastle.jsse.provider.ProvTlsClient.getSupportedCipherSuites(Unknown Source)
    org.bouncycastle.tls.AbstractTlsClient.init(Unknown Source)
    org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
    org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
    org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
    sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
    sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:167)
    sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1031)
    sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
    org.jasig.cas.client.validation.Saml11TicketValidator.retrieveResponseFromServer(Saml11TicketValidator.java:216)

In case, I have opened the issue #514 on BouncyCastle GitHub.

3

There are 3 best solutions below

6
Scimitar On

What you are seeing is consistent with the BouncyCastle JCE Provider not being registered. Hence the search for the ECDH Agreement is not finding it in the JCE search path.

To register the Provider dynamically simply add the following lines to your code

Security.addProvider(new BouncyCastleProvider());
Security.addProvider(new BouncyCastleJsseProvider());

as per the BouncyCastle Specifications section 6.1 and the test sample code BouncyCastle JSSE Test Code

I suspect that you are not correctly initiating the environment

0
dulon On

This problem was solved in https://github.com/bcgit/bc-java/issues/514 by anthony-o as it was caused by a re-packaging issue.

However, that solution did not work for me as my bouncycastle jars are not repackaged into shade/fat jars

Here is how I solved the issue: https://stackoverflow.com/a/59845413/497378

(I am not sure of the etiquette of posting link to answers from another stackoverflow question so please delete if not appropriate)

0
lapo On
java.lang.SecurityException: JCE cannot authenticate the provider BC

I get the same error (and the JAR was directly from Maven, no repackaging was in place), I think because starting in BC 1.61 release JARs are signed using a more recent signature algorithm (or root certificate) that Java 6 is unable to verify.

By downgrading BC to 1.60 I managed to connect to a SNI-enabled TLS server (which wasn't reachable usually by Java 6). I used the following Maven dependency:

<dependency groupId="org.bouncycastle" artifactId="bctls-jdk15on" version="1.60"/>