kjur / jsrsasign

The 'jsrsasign' (RSA-Sign JavaScript Library) is an opensource free cryptography library supporting RSA/RSAPSS/ECDSA/DSA signing/validation, ASN.1, PKCS#1/5/8 private/public key, X.509 certificate, CRL, OCSP, CMS SignedData, TimeStamp, CAdES and JSON Web Signature/Token in pure JavaScript.
https://kjur.github.io/jsrsasign
Other
3.25k stars 646 forks source link

JWS, ES512: Invalid signed JWTs due to invalid signature size #627

Open user163 opened 1 month ago

user163 commented 1 month ago

Some of the signed JWTs for ES512 generated with jsrsasign v11.1.0 in the context of JWS have signatures that are shorter than 132 bytes (e.g. 130 bytes). Such signatures and thus the associated signed JWTs are invalid and are verified as invalid by other JWS-compliant libraries.
With the 130 bytes signatures (at least the ones I have analyzed), r and s are only 65 bytes in size and the padding with a leading 0x00 on 66 bytes is missing for both values. So presumably the issue is a flawed implementation of the P1363 format.

In addition, there are also sporadic exceptions (unknown ECDSA sig s length error) during signing (with a frequency of approximately 1:1000).

Here is a script that demonstrates both issues:

// code takes a few minutes to execute!

var privateKey = `-----BEGIN PRIVATE KEY-----
MIH3AgEAMBAGByqGSM49AgEGBSuBBAAjBIHfMIHcAgEBBEIBt9JkMzOnDTkWGeWr
hq5a73ByFKDazPsiKSAyS7QrD9p7LY2fxpuJ33eccF4BlKcdUpH3JdBfQWLAhifA
t5vTRW6gBwYFK4EEACOhgYkDgYYABAGHGt/TynDUfNy8TII8lJOaRHezUbRooLM7
lCtkIejai/dZLbq9GUAeSG3dXujrx7lrElqbnFytJQgZ71OMOabmjAHEkJejYdC6
sGxsFCROu3oLZdNk8ZSY5pGIQj4CqLGthpgglVlfDQlQw2P3Ib0MP9r3TYaB6g8i
cx/Qwp4dqrtYug==
-----END PRIVATE KEY-----`;

// code for demonstrating different signature lengths
for (var i = 0; i < 16; i++) {
    var header = JSON.stringify({"alg": "ES512"});
    var payload = JSON.stringify({"sub": "1234567890", "name": "John Doe"});
    var jwt = KJUR.jws.JWS.sign("ES512", header, payload, privateKey);
    var signatureHex = b64utohex(jwt.split('.')[2]);
    var signatureLen = signatureHex.length/2;
    if (signatureLen != 132) console.log(signatureLen);
}
console.log("demo 1: done\n");

// code for demonstrating the exception "unknown ECDSA sig s length error"
for (var i = 0; i < 1024; i++) {
    var header = JSON.stringify({"alg": "ES512"});
    var payload = JSON.stringify({"sub": "1234567890", "name": "John Doe"});
    try {
        var jwt = KJUR.jws.JWS.sign("ES512", header, payload, privateKey);
    } catch(ex) {
        console.log(ex.message);
    }
}
console.log("demo 2: done");

Sample output:

130
130
130
130
demo 1: done

unknown ECDSA sig s length error
demo 2: done