From ee55742e733e842cc80f140ed0a2882493c9b55a Mon Sep 17 00:00:00 2001 From: Joakim Antman Date: Sat, 5 Sep 2026 22:10:25 +0300 Subject: [PATCH] Fix the RSA-PSS guard skipping the whole jwt_spec file The guard sat in the body of the ES loop rather than inside its context, so it registered on the top-level describe four times and gated every example in the file. Forcing the condition skipped 130 examples, not the 16 ECDSA ones, meaning any build without OpenSSL::PKey::RSA#sign_pss would have reported jwt_spec green while running none of it. It was also on the wrong loop. ECDSA does not need sign_pss; the PS examples do, and they had no guard at all. Moved there it skips 12. While in the ES context, 'should generate a valid token' was a byte for byte copy of the decode example next to it, so nothing covered what the encoder produced. It now asserts the segments, leaving the signature to the decode example, since ECDSA signatures are not deterministic and re-verifying one here would mean rebuilding raw-to-ASN.1 in a spec. Base64.strict_encode64 pads and uses the standard alphabet, neither of which matches a JWT segment. The PS assertion only passed because {"alg":"PS256"} is 15 bytes; the same assertion for ES256K fails. Also drop the :wrong_rsa_private fixture entry, which pointed at a public key file and was referenced nowhere. --- spec/jwt/jwt_spec.rb | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/spec/jwt/jwt_spec.rb b/spec/jwt/jwt_spec.rb index ba115833..735b9bb6 100644 --- a/spec/jwt/jwt_spec.rb +++ b/spec/jwt/jwt_spec.rb @@ -12,7 +12,6 @@ :secret => 'My$ecretK3y', :rsa_private => test_pkey('rsa-2048-private.pem'), :rsa_public => test_pkey('rsa-2048-public.pem'), - :wrong_rsa_private => test_pkey('rsa-2048-wrong-public.pem'), :wrong_rsa_public => test_pkey('rsa-2048-wrong-public.pem'), 'ES256_private' => test_pkey('ec256-private.pem'), 'ES256_public' => test_pkey('ec256-public.pem'), @@ -160,10 +159,6 @@ end %w[ES256 ES384 ES512 ES256K].each do |alg| - before do - skip 'OpenSSL gem missing RSA-PSS support' unless OpenSSL::PKey::RSA.method_defined?(:sign_pss) - end - context "alg: #{alg}" do before(:each) do data[alg] = JWT.encode(payload, data["#{alg}_private"], alg) @@ -172,10 +167,11 @@ let(:wrong_key) { OpenSSL::PKey::EC.generate(data["#{alg}_private"].group.curve_name) } it 'should generate a valid token' do - jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg + header, body, signature = data[alg].split('.') - expect(header['alg']).to eq alg - expect(jwt_payload).to eq payload + expect(header).to eql(Base64.urlsafe_encode64({ alg: alg }.to_json, padding: false)) + expect(body).to eql(Base64.urlsafe_encode64(payload.to_json, padding: false)) + expect(signature).not_to be_empty end it 'should decode a valid token' do @@ -202,6 +198,8 @@ %w[PS256 PS384 PS512].each do |alg| context "alg: #{alg}" do before(:each) do + skip 'OpenSSL gem missing RSA-PSS support' unless OpenSSL::PKey::RSA.method_defined?(:sign_pss) + data[alg] = JWT.encode payload, data[:rsa_private], alg end @@ -212,8 +210,8 @@ header, body, signature = token.split('.') - expect(header).to eql(Base64.strict_encode64({ alg: alg }.to_json)) - expect(body).to eql(Base64.strict_encode64(payload.to_json)) + expect(header).to eql(Base64.urlsafe_encode64({ alg: alg }.to_json, padding: false)) + expect(body).to eql(Base64.urlsafe_encode64(payload.to_json, padding: false)) # Validate signature is made of up header and body of JWT translated_alg = alg.gsub('PS', 'sha')