JimBob
JimBob

Reputation: 174

Bouncy Castle and WebPush: NoSuchMethodError: org.bouncycastle.math.ec.ECCurve$Fp

I'm trying to extend and existing web app (I don't have control of) with a jar extension to add push notification feature. I tried to follow the instructions here:

https://github.com/web-push-libs/webpush-java/wiki/Usage-Example

But when BouncyCastle comes into play I'm getting the following exception:

java.lang.NoSuchMethodError: org.bouncycastle.math.ec.ECCurve$Fp.<init>(Ljava/math/BigInteger;Ljava/math/BigInteger;Ljava/math/BigInteger;)V

while processing nl.martijndwars.webpush.Utils.loadPublicKey(String) method.

    public static PublicKey loadPublicKey(String encodedPublicKey) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
    byte[] decodedPublicKey = Base64Encoder.decode(encodedPublicKey);
    KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM, PROVIDER_NAME);
    ECParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(CURVE);
    ECCurve curve = parameterSpec.getCurve();
    ECPoint point = curve.decodePoint(decodedPublicKey);
    ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, parameterSpec);

    return keyFactory.generatePublic(pubSpec);
}

The return-line then throws the exception. The spi instance of the keyFactory is "org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi$ECDH@5a15f280" which also seems right...

Im using the jar via maven. "Luckily" the parent web application brings BouncyCastle on it's own in Version 1.54. That's the dependency in the web apps pom.xml

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.54</version>
        </dependency>

Which actually should exactly match the library's version (e.g. https://github.com/web-push-libs/webpush-java/blob/master/build.gradle)

And when I call java.security.Security.getProviders() I'm getting a list that already contains 'BCFIPS version 1.01, BC version 1.54', which is because the parent application already provides it during runtime.

When checking out the sources (http://javadox.com/org.bouncycastle/bcprov-jdk15on/1.53/org/bouncycastle/math/ec/ECCurve.Fp.html for instance) the constructor exists.

I also tried to remove and add the BouncyCastleProvider from java.security.Security before executing the code.

EDIT#1:

I've made some progress in understanding the issue. I noticed that the web-server jre has a external library (bc-fips-1.0.1.jar) which seems to bring another implementation of org.bouncycastle.math.ec.ECCurve$Fp. This jar also seems to be the reason for the 'BCFIPS version 1.01' security provider.

By calling keyFactory.generatePublic(pubSpec) is seem that the KeyFactory somehow (classloading issue I guess) uses the other version ECCurve$Fp that really does not have the constructor from the error message.

EDIT#2:

I've debugged a while and could proof my theory. The WepAppClassloader picks the class from the lib-folder (which is the wrong one). Now I've tried somehow to preload the correct class for the right jar. But this does not seems to work.

EDIT#3:

The final solution for me was to repackage the bouncy castle lib. Not nice but I had no ideas anymore.

Upvotes: 2

Views: 2329

Answers (1)

Arshad Noor
Arshad Noor

Reputation: 11

The problem is that you have two SecurityProviders from BouncyCastle in your distribution - the FIPS certified version, as well as the regular version. You need to remove the FIPS version if you want to use the specifc method that's throwing the exception.

Once you remove it, that part of the code will work fine, but its possible that other parts that are dependent on the FIPS certified library may not work. Ideally, you should be using only one or the other JAR - not both; so you may need to refactor your code for what you want.

Upvotes: 0

Related Questions