Bug in Keycloak package? ( ECDSA KeyFactory not available )

2.3k views Asked by At

When running my keycloak application, the following error appears:

java.security.NoSuchAlgorithmException: ECDSA KeyFactory not available
    at java.base/java.security.KeyFactory.<init>(KeyFactory.java:138) ~[na:na]
    at java.base/java.security.KeyFactory.getInstance(KeyFactory.java:183) ~[na:na]
    at org.keycloak.jose.jwk.JWKParser.createECPublicKey(JWKParser.java:107) ~[keycloak-core-15.0.2.jar:15.0.2]
    ... 61 common frames omitted

After doing some digging, found out KeyFactory cannot settle "ECDSA" as an algorithm and therefore I should use the "EC" algorithm to generate public key.

But if KeyFactory doesnt support "ECDSA" as an algorithm, why does Keycloak-15.0.2 JWKParser class' createECPublicKey func remain trying to generate a public key with ECDSA?

try {
            ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(name);
            ECNamedCurveSpec params = new ECNamedCurveSpec("prime256v1", spec.getCurve(), spec.getG(), spec.getN());
            ECPoint point = new ECPoint(x, y);
            ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);

            KeyFactory kf = KeyFactory.getInstance("ECDSA");
            return kf.generatePublic(pubKeySpec);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

Is this a bug? or am I juts completely missing something?

2

There are 2 answers

2
Robert On

Your main problem is that you forgot to tell KeyFactory.getInstance that ECDSA is from BouncyCastle provider.

You add this, KeyFactory.getInstance("ECDSA"); will work:

public static final Provider BC = new BouncyCastleProvider();

...

public static void myMethod() {
    ...
    KeyFactory kf = KeyFactory.getInstance("ECDSA", BC);
}

Alternatively you can add BouncyCastleProvider to your list of providers:

Security.addProvider(new BouncyCastleProvider());
0
Mantamathic On

In case somebody still has struggles even after doing the proposed answer:

I got the same issue running this code inside a docker container and an osgi BundleActivator even when executing the "Security.addProvider(new BouncyCastleProvider());". For my case, the problem occurred because I added the Provider in a Bundleactivator like this:

        Security.addProvider(new BouncyCastleProvider());

But after building my project, it tried to execute the addProvider again, but it did not do anything, because a Provider was already there from the docker startup bundle activation, but the old provider seemed to be outdated. Debugging into this, I found "Unable to load class 'org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi$ECDSA' because the bundle wiring for myBundle is no longer valid." after calling KeyFactory.getInstance("ECDSA", BouncyCastleProvider.PROVIDER_NAME).

So the solution in this case was just to remove and re-add this again:

public void start(final BundleContext bundleContext) throws Exception {
    // removing the initial BouncyCastleProvider to cleanly re-add it avoids the "ECDSA Keyfactory not available" error
    if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) != null) {
        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
    }
    // add BouncyCastle as security provider, since it is required by the keycloak filter adapter
    Security.addProvider(new BouncyCastleProvider());
}