javajwtcryptographybouncycastlenimbus

Could not verify JWT with Curve secp256k1 in java


I am signing the JWT token using the EC key, Code to create Keys:

ECKey ecKey = new ECKeyGenerator(Curve.SECP256K1)
                    .keyUse(KeyUse.SIGNATURE)
                    .keyID(keyId)
                    .provider(BouncyCastleProviderSingleton.getInstance())
                    .generate();

After creating a keypair, I created publicKeyJwk which is hosted in public API for verification of JWT

{
    "kty": "EC",
    "x": "hZvJ0heaxQxeeBXlSuC-4IPx_UFGeOL5UEYLzLdzfIQ",
    "y": "EufmJauadvvkKl7lB7HkzzF9AIVLx4qN9Ih5yf-7eLc",
    "crv": "secp256k1"
}

When I try to verify the signature using code verification code :

Provider bc = BouncyCastleProviderSingleton.getInstance();
Security.addProvider(bc);
ECKey ecKey = new ECKey.Builder(Curve.parse("secp256k1"),new Base64URL(x),new Base64URL(y)).build();
ECPublicKey ecPublicKey = ecKey.toECPublicKey();
ECDSAVerifier ecdsaVerifier = new ECDSAVerifier(ecPublicKey);
boolean verify = jwt.verify(ecdsaVerifier);

I am getting this error:

java.security.SignatureException: Curve not supported: java.security.spec.ECParameterSpec@25a6944c
    at jdk.crypto.ec/sun.security.ec.ECDSASignature.lambda$engineVerify$0(ECDSASignature.java:493)
    at java.base/java.util.Optional.orElseThrow(Optional.java:403)
    at jdk.crypto.ec/sun.security.ec.ECDSASignature.engineVerify(ECDSASignature.java:493)
    at java.base/java.security.Signature$Delegate.engineVerify(Signature.java:1422)
    at java.base/java.security.Signature.verify(Signature.java:790)
    at com.nimbusds.jose.crypto.ECDSAVerifier.verify(ECDSAVerifier.java:201)
    at com.nimbusds.jose.JWSObject.verify(JWSObject.java:376)

Runtime: Java: openjdk 17.0.9 2023-10-17

nimbus-jose-jwt:9.37.1

bcprov-jdk18on:1.77

Could someone please provide guidance on what might be wrong here?


Solution

  • As of Java 161, there is no built-in support for secp256k1, so a third-party provider is required, e.g. BouncyCastle, as you already do for key generation.

    For verification, the following must be added to your code:

    import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;
    ...
    ECDSAVerifier ecdsaVerifier = new ECDSAVerifier(ecPublicKey);
    ecdsaVerifier.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance()); // add
    

    see also here.


    1 secp256k1 is already disabled by default in Java 15, but can be enabled.