Skip to content

Commit 6c9dc8f

Browse files
jonmchananakinj
authored andcommitted
Raise DecodeError on empty hmac_secret addressing OpenSSL 3.0 issue; Fixes #526
1 parent 6c73c7b commit 6c9dc8f

File tree

3 files changed

+114
-2
lines changed

3 files changed

+114
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ puts decoded_token
7777
* HS512 - HMAC using SHA-512 hash algorithm
7878

7979
```ruby
80-
# The secret must be a string. A JWT::DecodeError will be raised if it isn't provided.
80+
# The secret must be a string. With OpenSSL 3.0, JWT::DecodeError will be raised if it isn't provided.
8181
hmac_secret = 'my$ecretK3y'
8282

8383
token = JWT.encode payload, hmac_secret, 'HS256'

lib/jwt/algos/hmac.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,15 @@ def sign(algorithm, msg, key)
1313
if authenticator && padded_key
1414
authenticator.auth(padded_key, msg.encode('binary'))
1515
else
16-
OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub('HS', 'sha')), key, msg)
16+
begin
17+
OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub('HS', 'sha')), key, msg)
18+
rescue OpenSSL::HMACError => e
19+
if key == '' && e.message == 'EVP_PKEY_new_mac_key: malloc failure'
20+
raise JWT::DecodeError.new('OpenSSL 3.0 does not support nil or empty hmac_secret')
21+
end
22+
23+
raise e
24+
end
1725
end
1826
end
1927

spec/jwt/algos/hmac_spec.rb

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe ::JWT::Algos::Hmac do
4+
describe '.sign' do
5+
subject { described_class.sign('HS256', 'test', hmac_secret) }
6+
7+
# Address OpenSSL 3.0 errors with empty hmac_secret - https://github.com/jwt/ruby-jwt/issues/526
8+
context 'when nil hmac_secret is passed' do
9+
let(:hmac_secret) { nil }
10+
context 'when OpenSSL 3.0 raises a malloc failure' do
11+
before do
12+
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('EVP_PKEY_new_mac_key: malloc failure'))
13+
end
14+
15+
it 'raises JWT::DecodeError' do
16+
expect { subject }.to raise_error(JWT::DecodeError, 'OpenSSL 3.0 does not support nil or empty hmac_secret')
17+
end
18+
end
19+
20+
context 'when OpenSSL raises any other error' do
21+
before do
22+
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('Another Random Error'))
23+
end
24+
25+
it 'raises the original error' do
26+
expect { subject }.to raise_error(OpenSSL::HMACError, 'Another Random Error')
27+
end
28+
end
29+
30+
context 'when other versions of openssl do not raise an exception' do
31+
let(:response) { Base64.decode64("Q7DO+ZJl+eNMEOqdNQGSbSezn1fG1nRWHYuiNueoGfs=\n") }
32+
before do
33+
allow(OpenSSL::HMAC).to receive(:digest).and_return(response)
34+
end
35+
36+
it { is_expected.to eql(response) }
37+
end
38+
end
39+
40+
context 'when blank hmac_secret is passed' do
41+
let(:hmac_secret) { '' }
42+
context 'when OpenSSL 3.0 raises a malloc failure' do
43+
before do
44+
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('EVP_PKEY_new_mac_key: malloc failure'))
45+
end
46+
47+
it 'raises JWT::DecodeError' do
48+
expect { subject }.to raise_error(JWT::DecodeError, 'OpenSSL 3.0 does not support nil or empty hmac_secret')
49+
end
50+
end
51+
52+
context 'when OpenSSL raises any other error' do
53+
before do
54+
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('Another Random Error'))
55+
end
56+
57+
it 'raises the original error' do
58+
expect { subject }.to raise_error(OpenSSL::HMACError, 'Another Random Error')
59+
end
60+
end
61+
62+
context 'when other versions of openssl do not raise an exception' do
63+
let(:response) { Base64.decode64("Q7DO+ZJl+eNMEOqdNQGSbSezn1fG1nRWHYuiNueoGfs=\n") }
64+
before do
65+
allow(OpenSSL::HMAC).to receive(:digest).and_return(response)
66+
end
67+
68+
it { is_expected.to eql(response) }
69+
end
70+
end
71+
72+
context 'when hmac_secret is passed' do
73+
let(:hmac_secret) { 'test' }
74+
context 'when OpenSSL 3.0 raises a malloc failure' do
75+
before do
76+
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('EVP_PKEY_new_mac_key: malloc failure'))
77+
end
78+
79+
it 'raises the original error' do
80+
expect { subject }.to raise_error(OpenSSL::HMACError, 'EVP_PKEY_new_mac_key: malloc failure')
81+
end
82+
end
83+
84+
context 'when OpenSSL raises any other error' do
85+
before do
86+
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('Another Random Error'))
87+
end
88+
89+
it 'raises the original error' do
90+
expect { subject }.to raise_error(OpenSSL::HMACError, 'Another Random Error')
91+
end
92+
end
93+
94+
context 'when other versions of openssl do not raise an exception' do
95+
let(:response) { Base64.decode64("iM0hCLU0fZc885zfkFPX3UJwSHbYyam9ji0WglnT3fc=\n") }
96+
before do
97+
allow(OpenSSL::HMAC).to receive(:digest).and_return(response)
98+
end
99+
100+
it { is_expected.to eql(response) }
101+
end
102+
end
103+
end
104+
end

0 commit comments

Comments
 (0)