jonasroussel / dart_jsonwebtoken

A dart implementation of the famous javascript library 'jsonwebtoken'
MIT License
87 stars 29 forks source link

Token signature with ES512 is invalid #51

Closed nassbe closed 8 months ago

nassbe commented 8 months ago

Hi Guys, i'm currently implementing a test app that creates JWT for testing purposes. I want to use ES512 algorithm and a given private key and certChain from my "counterpart" for first testing. This key has a size of 521 bits as it is the standard for ES512.

My Problem

The problem is, that JWT.sign() constantly returns tokens with invalid signatures according to jwt.io and also (in perhaps 3 out of 4 cases) according to JWT.verify(). I checked multiple times that the key and certChain are a valid pair and the header and payload are handed over correctly.

My Analysis

I took a closer look at the difference between the signatures and the first thing i noticed was that the signature from jwt.io is constantly 176 characters long while the signature from my app had only 174 characters. After taking a closer look into the implementation of the ECDSAAlgorithm's sign function in algorithms.dart, i noticed that the signature get's "cut" to privateKey.size*2 bytes image (in this case 130 bytes), although it should be 132 bytes (at least that's how it worked fine). I guess this is because the size of the key is actually 65.125 bytes so the S and R part of the signature that's returned by signer.generateSignature() can have a length of 66 bytes (that can be observed by using different payloads), but i'm really not an expert at this topic ;)

My Fix

I set the size of my bytes list to 132 (using (privateKey.key.parameters!.curve.fieldSize/8).ceil()*2, probably not the best way but it worked out for me). Because the bigInts that are returned by signer.generateSignature() can have a length of 65 or 66 bytes after converting them into Uint8Lists, i filled the byte-List like that: image

This way i got signatures with always the same length that are simply filled with 0 at the first (or middle) position if the rBytes or sBytes isn't long enough. The created tokens are always valid according to jwt.io and jwt.verify() now.

I hope i provided you enough information to understand my problem :) Unfortunately i could really not use the library with my key to get valid tokens so maybe this issue is relevant for other people as well

jonasroussel commented 8 months ago

Hi @nassbe,

Thank you for your detailed analysis. I have reviewed your findings, and your approach seems to work well. In fact, 3 years ago when implementing the signature process to follow the RFC 7519, I realized that I forgot to implement the padding required for keys that are not a multiple of 8.

I will publish a new patch with your fix soon. Once the patch is deployed, please feel free to test it on your end and let me know if everything is working as expected.

jonasroussel commented 8 months ago

And this is the new published version: https://pub.dev/packages/dart_jsonwebtoken/versions/2.13.0

nassbe commented 8 months ago

After a few tests, it looks like everything is working perfectly. Thanks! 😄