Skip to content

Commit d9266a2

Browse files
authored
Check signing and verification key type for ECDSA algorithm (#688)
1 parent 98d238b commit d9266a2

File tree

6 files changed

+58
-5
lines changed

6 files changed

+58
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
**Features:**
88

99
- Add support for x5t header parameter for X.509 certificate thumbprint verification [#669](https://github.com/jwt/ruby-jwt/pull/669) ([@hieuk09](https://github.com/hieuk09))
10+
- Raise an error if the ECDSA signing or verification key is not an instance of `OpenSSL::PKey::EC` [#688](https://github.com/jwt/ruby-jwt/pull/688) ([@anakinj](https://github.com/anakinj))
1011
- Your contribution here
1112

1213
**Fixes and enhancements:**

lib/jwt/jwa/ecdsa.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@ def initialize(alg, digest)
1212
end
1313

1414
def sign(data:, signing_key:)
15+
raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::EC instance.") unless signing_key.is_a?(::OpenSSL::PKey::EC)
16+
1517
curve_definition = curve_by_name(signing_key.group.curve_name)
1618
key_algorithm = curve_definition[:algorithm]
19+
1720
raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} signing key was provided" if alg != key_algorithm
1821

1922
asn1_to_raw(signing_key.dsa_sign_asn1(digest.digest(data)), signing_key)
2023
end
2124

2225
def verify(data:, signature:, verification_key:)
26+
raise_verify_error!("The given key is a #{verification_key.class}. It has to be an OpenSSL::PKey::EC instance.") unless verification_key.is_a?(::OpenSSL::PKey::EC)
27+
2328
curve_definition = curve_by_name(verification_key.group.curve_name)
2429
key_algorithm = curve_definition[:algorithm]
2530
raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} verification key was provided" if alg != key_algorithm

spec/jwt/jwa/ecdsa_spec.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,40 @@
5555
end.to raise_error(JWT::VerificationError, 'Signature verification raised')
5656
end
5757
end
58+
59+
context 'when the verification key is not an OpenSSL::PKey::EC instance' do
60+
it 'raises a JWT::DecodeError' do
61+
expect do
62+
instance.verify(data: data, signature: '', verification_key: 'not_a_key')
63+
end.to raise_error(JWT::DecodeError, 'The given key is a String. It has to be an OpenSSL::PKey::EC instance.')
64+
end
65+
end
66+
end
67+
68+
describe '#sign' do
69+
context 'when the signing key is valid' do
70+
it 'returns a valid signature' do
71+
signature = instance.sign(data: data, signing_key: ecdsa_key)
72+
expect(signature).to be_a(String)
73+
expect(signature.length).to be > 0
74+
end
75+
end
76+
77+
context 'when the signing key is not an OpenSSL::PKey::EC instance' do
78+
it 'raises a JWT::DecodeError' do
79+
expect do
80+
instance.sign(data: data, signing_key: 'not_a_key')
81+
end.to raise_error(JWT::EncodeError, 'The given key is a String. It has to be an OpenSSL::PKey::EC instance.')
82+
end
83+
end
84+
85+
context 'when the signing key is invalid' do
86+
it 'raises a JWT::DecodeError' do
87+
invalid_key = OpenSSL::PKey::EC.generate('sect571r1')
88+
expect do
89+
instance.sign(data: data, signing_key: invalid_key)
90+
end.to raise_error(JWT::DecodeError, "The ECDSA curve 'sect571r1' is not supported")
91+
end
92+
end
5893
end
5994
end

spec/jwt/jwk/decode_with_jwk_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@
169169

170170
it 'fails in some way' do
171171
expect { described_class.decode(signed_token, nil, true, algorithms: ['ES384'], jwks: jwks) }.to(
172-
raise_error(NoMethodError, /undefined method .*group/)
172+
raise_error(JWT::DecodeError, 'The given key is a String. It has to be an OpenSSL::PKey::EC instance.')
173173
)
174174
end
175175
end

spec/jwt/jwk/ec_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,22 @@
110110
end
111111
end
112112

113+
describe '.to_openssl_curve' do
114+
context 'when a valid curve name is given' do
115+
it 'returns the corresponding OpenSSL curve name' do
116+
expect(JWT::JWK::EC.to_openssl_curve('P-256')).to eq('prime256v1')
117+
expect(JWT::JWK::EC.to_openssl_curve('P-384')).to eq('secp384r1')
118+
expect(JWT::JWK::EC.to_openssl_curve('P-521')).to eq('secp521r1')
119+
expect(JWT::JWK::EC.to_openssl_curve('P-256K')).to eq('secp256k1')
120+
end
121+
end
122+
context 'when an invalid curve name is given' do
123+
it 'raises an error' do
124+
expect { JWT::JWK::EC.to_openssl_curve('invalid-curve') }.to raise_error(JWT::JWKError, 'Invalid curve provided')
125+
end
126+
end
127+
end
128+
113129
describe '.import' do
114130
subject { described_class.import(params) }
115131
let(:include_private) { false }

spec/jwt/jwt_spec.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,6 @@
3939
}
4040
end
4141

42-
after(:each) do
43-
expect(OpenSSL.errors).to be_empty
44-
end
45-
4642
context 'alg: NONE' do
4743
let(:alg) { 'none' }
4844
let(:encoded_token) { data['NONE'] }

0 commit comments

Comments
 (0)