Description
Version(s) affected
3.2.8
Description
Hi folks, I'm issuing a JWT signed with EdDSA (ed25519) using web-token\jwt-framework and trying to validate it using nodej's jose but the validation fails complaining that signature is invalid.
With jwt-framework I can verify a token issued and signed by nodej's jose using the same EdDSA key and I can also verify with jwt-framework a JWT signed by jwt-framework in jwt-framework with this EdDSA key.
Other EC algorithms like ES256 also works perfectly between the two libs. I can also validate other tokens issued in other languages using EdDSA in nodejs. So far only EdDSA tokens signed in PHP are failing.
Can someone help me figure out if I'm doing something wrong or if there is some interoperability issue between those two implementations?
Thanks in advance for any help and congrats for the great work done so far!
How to reproduce
Forgive me if you find any typos. Had to copy and paste partial lines of code.
create an ed25519 key pair using openssl:
openssl genpkey -algorithm Ed25519 -out ed25519_private_key.pem
openssl pkcs8 -topk8 -nocrypt -in ed25519_private_key.pem -out ed25519_private_key_pkcs8.pem
openssl pkey -in ed25519_private_key.pem -pubout -out ed25519_public_key.pem
Issue a signed JWS with web-token/jwt-framework and write it to file.
use Jose\Component\KeyManagement\JWKFactory;
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Signature\JWSVerifier;
use Jose\Component\Core\JWK;
use Jose\Component\Signature\Algorithm\EdDSA;
use Jose\Component\Signature\Algorithm\ES256;
use Jose\Component\Signature\JWSBuilder;
use Jose\Component\Signature\Serializer\CompactSerializer as JWSCompactSerializer;
use Jose\Component\Signature\Serializer\JWSSerializer;
//CONST ALG = 'ES256';
//const CHAVE_PRIVADA_PKCS8 = './keys/ES256/ecdsa-p256_private_key_pkcs8.pem';
//const CHAVE_PUBLICA = './keys/ES256/ecdsa-p256_public_key.pem';
CONST ALG = 'EdDSA';
const CHAVE_PRIVADA_PKCS8 = './keys/EdDSA/ed25519_private_key_pkcs8.pem';
const CHAVE_PUBLICA = './keys/EdDSA/ed25519_public_key.pem';
$chavePrivada = JWKFactory::createFromKeyFile(CHAVE_PRIVADA_PKCS8);
$chavePublica = JWKFactory::createFromKeyFile(CHAVE_PUBLICA);
$payload = [
'exp' => time() + 60 * 50,
'iss' => 'rebels',
'sub' => '78286616731',
'aud' => 'ghost',
'iat' => time(),
'name' => 'Ezra Bridger',
'deviceid' => '3c512309-57ca-47bf-8543-c2f1cec1189a',
];
$algorithmManager = new AlgorithmManager([
new ES256(),
new EdDSA(),
]);
$jwsBuilder = new JWSBuilder($algorithmManager);
$jws = $jwsBuilder
->create()
->withPayload(json_encode($payload))
->addSignature($chavePrivada, ['alg' => ALG])
->build();
$serializer = new JWSCompactSerializer();
$token = $serializer->serialize($jws, 0);
file_put_contents('./output/php-jws.'. ALG . '.txt', $token);
// $token = file_get_contents('./output/node-jws.txt');
$jwsVerifier = new JWSVerifier($algorithmManager);
$jwsVerifier->verifyWithKey($jws, $chavePrivada, 0);
read it on nodejs and validate the JWT
import { jwtVerify, importSPKI, decodeProtectedHeader } from 'jose';
import { readFileSync } from 'fs';
async function validateJWT(filename, publicKeyFile) {
const jwt = readFileSync(filename).toString();
const protectedHeader = decodeProtectedHeader(jwt);
console.log(protectedHeader);
const publicKeyPartner = await importSPKI(readFileSync(publicKeyFile).toString());
const verifiedJWT = await jwtVerify(jwt, publicKeyPartner);
return verifiedJWT;
}
validateJWT('./output/php-jws.ES256.txt', './keys/ES256/ecdsa-p256_public_key.pem');
validateJWT('./output/php-jws.EdDSA.txt', './keys/EdDSA/ed25519_public_key.pem');
To generate ES256 keys with openssl:
openssl ecparam -genkey -name prime256v1 -noout -out ecdsa-p256-private.pem
openssl pkcs8 -topk8 -nocrypt -in ecdsa-p256-private.pem -out ecdsa-p256-private.p8
openssl ec -in ecdsa-p256-private.pem -pubout -out ecdsa-p256-public.pem
Possible Solution
No response
Additional Context
Node version: v20.5.0
node jose version: 4.13.1
Error message from nodes
file:///home/user/jwt/node_modules/jose/dist/node/esm/jws/flattened/verify.js:87
throw new JWSSignatureVerificationFailed();
^
JWSSignatureVerificationFailed: signature verification failed
at flattenedVerify (file:///home/user/jwt/node_modules/jose/dist/node/esm/jws/flattened/verify.js:87:15)
at async compactVerify (file:///home/user/jwt/node_modules/jose/dist/node/esm/jws/compact/verify.js:15:22)
at async jwtVerify (file:///home/user/jwt/node_modules/jose/dist/node/esm/jwt/verify.js:6:22)
at async validateJWT (file:///home/user/jwt/node-read.mjs:9:23) {
code: 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED'
}