3
votes

i need some help to validate a jwt signature with a ECDSA public key. I'm reading the key from a .pem file with bouncy castle and using jjwt to do the validation. I'm getting an error while validating the signature.

Security.addProvider(new BouncyCastleProvider());
String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJtc2kiOiI5NzE1NTA5ODc2NTUiLCJmZWEiOiJzaWdudXAtZGF0YSIsImlzcyI6IkNEUCIsImV4cCI6MTU1NDU2NjMzNiwiaWF0IjoxNTU0MzkzNTM2LCJzaWQiOiIwNDI0MDMwMDg5NzI4MTg3QG5haS5lcGMubW5jMTMwLm1jYzMxMC4zZ3BwbmV0d29yay5vcmcifQ.RwxoGmFd1_dQPeGN-0gnWIW79xXvGHoyJKBbCKajgO75UooceS6tskxwqViEuP1gZD66UE8Bd2L0FaeI2aS_IA";
PemReader pemReader = new PemReader(new FileReader("/publickey.pem"));
X509EncodedKeySpec spec = new X509EncodedKeySpec(pemReader.readPemObject().getContent());
KeyFactory kf = KeyFactory.getInstance("ECDSA","BC");
PublicKey publicKey = kf.generatePublic(spec);
Jws<Claims> claims = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(jwt);

I'm getting a Signature Exception with: Unable to verify Elliptic Curve signature using configured ECPublicKey. error decoding signature bytes.

2
Was the jwt string not encrypted with the private key that matches the public key? Post the private key along with the original jwt token so people can verify what you're doing. Maybe client code / command for your encryption as well.Kieveli
I only have the public key. What you mean with the original jwt?Spermato
If I'm understanding what's going on here, your jwt string is signed via the private key by the client. Verifying the signature via the public key, which matches the private key, will reveal two things: 1) the original jwt is valid, and 2) verification that the owner of the private key sent the request. The error indicates one of two things: the signature isn't created correctly via the private key, or the public key you have does not match the private key used. I don't think there's enough information here to help you yet (Maybe I'm wrong though!)Kieveli
It's even possible that the client didn't use the same Elliptic Curve algorithm for signing...Kieveli

2 Answers

5
votes

This will work as well without mentioning any algorithm.

public boolean isTokenValid(String token) {
    try {
        String certificate = "GET_YOUR_PUBLIC_CERTIFICATE_HERE"; //Either from REST call or reading from a cert file.
        getPublicKeyAndParseToken(token, certificate);
        return true;
    } catch (IOException e) {
        log.error("", e);
    } catch (Exception e) {
        log.error("", e);
        log.error("JWT Not-Verified");
    }
    return false;
}

private void getPublicKeyAndParseToken(String token, String certificate) throws IOException, CertificateException {
    log.debug("Certificate:: " + certificate); //Only for debugging purpose
    InputStream is = new ByteArrayInputStream(certificate.getBytes(StandardCharsets.UTF_8));
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    Certificate cert = cf.generateCertificate(is);
    PublicKey publicKey = cert.getPublicKey();

    Jws parsedClaimsJws = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
    log.debug("Header:: " + parsedClaimsJws.getHeader()); //Only for debugging purpose
    log.debug("Body:: " + parsedClaimsJws.getBody()); //Only for debugging purpose
}

Don't forget to use version '0.9.x' of jjwt library. I've below dependency in my build.gradle:

compile('io.jsonwebtoken:jjwt:0.9.1')
1
votes

Problem found, i was using an old jjwt lib (0.6). Changed to 0.9 with the same code and it works as expected.

Thanks