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

Lax JWK Decoding Issue #591

Open madaster97 opened 1 year ago

madaster97 commented 1 year ago

Hi there,

If you format an RSA JWK in a slightly incorrect way, this tool will still count it as valid for validating JWTs. However, other tools such as JWT.IO and Microsoft libraries do not count these keys as correct, so using this tool can cause compatibility issues.

Details:

To start, JWT.IO does not like the invalid public key.

However, rsasignjs count this key as valid:

const KJUR = require("jsrsasign");

const jwt = "eyJraWQiOiJqd2stcnNhIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIwMTRmZjNmYy1jN2Y3LTQwZmYtOWEyYy1hZTlmMDNiNzljNDIiLCJhdWQiOiJodHRwczpcL1wvZXBpY3Byb3h5LW5wLmV0MDkxNS5lcGljaG9zdGVkLmNvbVwvRkhJUlByb3h5UE9DXC9vYXV0aDJcL3Rva2VuIiwiaXNzIjoiMDE0ZmYzZmMtYzdmNy00MGZmLTlhMmMtYWU5ZjAzYjc5YzQyIiwiZXhwIjoxNjg5Njg2OTc0LCJpYXQiOjE2ODk2ODY5MTQsImp0aSI6IjQ3ZDhhZjUxLTRjMjItNDA2MS04NmIzLWRlMmJhM2I5OTY0YSJ9.DO1jA1MgRvLvgKfxzSU2vZ7Xyv9Dh455gjNHrywyY2-I93iYqoRtYsB6IcocCGn_HXEqNKEWVWCNOnt834nipf50FNDRorD_zW-KOQ4Le8u82XPZyc0nqGb7cwNtPgMjpRFG-IH44AT4scScfhYRzKD7BWnLEzH3kfY1iPdcWvbPbPFgvJDsI2-nmPSGx7b5wSr8NH9xcYJD0jFhTVy-nl-zIXqE83-1ycqg7ufCxRWXyCI8sDR6jzytmg75X1hdZsJty1LQRWuZ3rD1RhofzypD8SpVQz5HZ2-xHjZGZDgokEaKqwu2M2qaKX0I6PNILmMJ4WVeIfWnF-3c68qwXw"
const key = KJUR.KEYUTIL.getKey({
  "kty": "RSA",
  "e": "AQAB",
  "use": "sig",
  "kid": "jwk-rsa",
  "n": "AKLMe2qRcXdeqtYEiA5Cv64eA3TOI_eoZbwoyl20E-skY4gCExE3BBugEdyFaKiopGVczSIQJwlzI2-mJYwMBz8iDsAx913E2it84LjTELP-9D5F1N9R50eH76raBq0SxfIx-vL0mVFX7o9A6032lnwMLI3Dhj2HxGD7ZVvaj7l2mypPA2zad6JkcS6XSugI-lXxWtTHln4FxtvG7kjEpBQtjZXcsJgU-wsxdxPRIxCtm0aznSogjHgrtSuD4nsN6OAiWz154JUCq0WcB6VBMR-LaH68iSWpAjyv4sMvEVXkOOr-vqXMAhsYedKWF2496bHUhDtGMqILqprqbed3Rz0="
})
const sigValid = KJUR.jws.JWS.verify(jwt, key);

console.log(sigValid) // should be false, but is true

Can you tell where the inconsistency is coming from? I've run into something like this before, and it could be because of missing padding on the raw "n" field of the keys.

madaster97 commented 1 year ago

For reference, here's the script I used to convert the "wrong" form of the public key into the right form, using JOSE v4.11.1:

const jose = require('jose');
(async () => {
    const key = await jose.importJWK({
        "kty": "RSA",
        "e": "AQAB",
        "use": "sig",
        "kid": "jwk-rsa",
        "n": "AKLMe2qRcXdeqtYEiA5Cv64eA3TOI_eoZbwoyl20E-skY4gCExE3BBugEdyFaKiopGVczSIQJwlzI2-mJYwMBz8iDsAx913E2it84LjTELP-9D5F1N9R50eH76raBq0SxfIx-vL0mVFX7o9A6032lnwMLI3Dhj2HxGD7ZVvaj7l2mypPA2zad6JkcS6XSugI-lXxWtTHln4FxtvG7kjEpBQtjZXcsJgU-wsxdxPRIxCtm0aznSogjHgrtSuD4nsN6OAiWz154JUCq0WcB6VBMR-LaH68iSWpAjyv4sMvEVXkOOr-vqXMAhsYedKWF2496bHUhDtGMqILqprqbed3Rz0="
    }, "RS256");
    const pub = await jose.exportSPKI(key);
    console.log(pub);

    const jwkPub = await jose.exportJWK(key);
    console.log(JSON.stringify(jwkPub,null,2));
})();
kjur commented 5 months ago

Hi @madaster97 , I got the issue. The n of wrong form has leading zero for two's supplement.

AKLMe2qRcXdeqt...
=>
00a2cc7b6a9171775... (in hexadecimal)

osx7apFxd16q1gSIDkK...
=>
  a2cc7b6a9171775...

I'll fix the issue.