0

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.

Anthony O.
  • 22,041
  • 18
  • 107
  • 163

3 Answers3

0

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

Scimitar
  • 61
  • 1
  • Thank you for your answer, I tested the `Security.addProvider` already, both with `Security.addProvider(new BouncyCastleJsseProvider());` (for which I had `NoSuchAlgorithmException: Algorithm ECDH not available` problem) & `Security.addProvider(new BouncyCastleJsseProvider(new BouncyCastleProvider()));` for which I had `JCE cannot authenticate the provider BC`... :/ – Anthony O. May 07 '19 at 21:13
  • My apologies. I did not fully read the steps that you had already tried. From the above comments 1) fails because BC provider is not registered and 2) also does not register BC - try Security.addProvider(new BouncyCastleProvider()); If this still gets the authentication error, then that is your actual problem. As a workaround to this you could try using openJDK 12 to bypass authentication if this is a possibility in tour environment – Scimitar May 08 '19 at 00:52
  • No I also tried your solution without any more succes (with your solution I still have the `Algorithm ECDH not available` problem, which I think is logic because `BouncyCastleJsseProvider` is used when I try to access an HTTPS URL, and it actually does not declare such algorithm and as far I have understood JCE when a provider is used, it can't access to things declared by other providers...). In my problem, I can't upgrade the JDK version because I'm stuck with JBoss 5.1 which can't run with anything newer than JDK 6... – Anthony O. May 09 '19 at 09:29
  • @AnthonyO. In fact providers can "access things declared by other providers". In particular, BouncyCastleJsseProvider asks for "ECDH" via the provider mechanism, and relies on some other provider (e.g. BouncyCastleProvider) to "provide" it. It appears the issue here may be as simple as not registering BOTH providers. – Peter Dettman May 14 '19 at 10:17
  • @PeterDettman well perhaps it is a bug but it doesn't seem to work like that, at least with JDK6: `BouncyCastleJsseProvider` doesn't manage to access ECDH provider provided by `BouncyCastleProvider` (I do register both providers & tested to register them in my webapp libs or in the JRE security system like explained in my question: both technics ended up with the same error message) – Anthony O. May 14 '19 at 11:19
  • Try downgrading BC to 1.60. (cfr. my anwser for more details) – lapo Aug 31 '20 at 15:51
0

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)

dulon
  • 735
  • 8
  • 10
0
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"/>
lapo
  • 3,136
  • 26
  • 34