Skip to content

Commit

Permalink
Raise DecodeError on empty hmac_secret addressing OpenSSL 3.0 issue; F…
Browse files Browse the repository at this point in the history
…ixes #526
  • Loading branch information
jonmchan authored and anakinj committed Oct 24, 2022
1 parent 6c73c7b commit 6c9dc8f
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ puts decoded_token
* HS512 - HMAC using SHA-512 hash algorithm

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

token = JWT.encode payload, hmac_secret, 'HS256'
Expand Down
10 changes: 9 additions & 1 deletion lib/jwt/algos/hmac.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,15 @@ def sign(algorithm, msg, key)
if authenticator && padded_key
authenticator.auth(padded_key, msg.encode('binary'))
else
OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub('HS', 'sha')), key, msg)
begin
OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub('HS', 'sha')), key, msg)
rescue OpenSSL::HMACError => e
if key == '' && e.message == 'EVP_PKEY_new_mac_key: malloc failure'
raise JWT::DecodeError.new('OpenSSL 3.0 does not support nil or empty hmac_secret')
end

raise e
end
end
end

Expand Down
104 changes: 104 additions & 0 deletions spec/jwt/algos/hmac_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# frozen_string_literal: true

RSpec.describe ::JWT::Algos::Hmac do
describe '.sign' do
subject { described_class.sign('HS256', 'test', hmac_secret) }

# Address OpenSSL 3.0 errors with empty hmac_secret - https://github.com/jwt/ruby-jwt/issues/526
context 'when nil hmac_secret is passed' do
let(:hmac_secret) { nil }
context 'when OpenSSL 3.0 raises a malloc failure' do
before do
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('EVP_PKEY_new_mac_key: malloc failure'))
end

it 'raises JWT::DecodeError' do
expect { subject }.to raise_error(JWT::DecodeError, 'OpenSSL 3.0 does not support nil or empty hmac_secret')
end
end

context 'when OpenSSL raises any other error' do
before do
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('Another Random Error'))
end

it 'raises the original error' do
expect { subject }.to raise_error(OpenSSL::HMACError, 'Another Random Error')
end
end

context 'when other versions of openssl do not raise an exception' do
let(:response) { Base64.decode64("Q7DO+ZJl+eNMEOqdNQGSbSezn1fG1nRWHYuiNueoGfs=\n") }
before do
allow(OpenSSL::HMAC).to receive(:digest).and_return(response)
end

it { is_expected.to eql(response) }
end
end

context 'when blank hmac_secret is passed' do
let(:hmac_secret) { '' }
context 'when OpenSSL 3.0 raises a malloc failure' do
before do
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('EVP_PKEY_new_mac_key: malloc failure'))
end

it 'raises JWT::DecodeError' do
expect { subject }.to raise_error(JWT::DecodeError, 'OpenSSL 3.0 does not support nil or empty hmac_secret')
end
end

context 'when OpenSSL raises any other error' do
before do
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('Another Random Error'))
end

it 'raises the original error' do
expect { subject }.to raise_error(OpenSSL::HMACError, 'Another Random Error')
end
end

context 'when other versions of openssl do not raise an exception' do
let(:response) { Base64.decode64("Q7DO+ZJl+eNMEOqdNQGSbSezn1fG1nRWHYuiNueoGfs=\n") }
before do
allow(OpenSSL::HMAC).to receive(:digest).and_return(response)
end

it { is_expected.to eql(response) }
end
end

context 'when hmac_secret is passed' do
let(:hmac_secret) { 'test' }
context 'when OpenSSL 3.0 raises a malloc failure' do
before do
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('EVP_PKEY_new_mac_key: malloc failure'))
end

it 'raises the original error' do
expect { subject }.to raise_error(OpenSSL::HMACError, 'EVP_PKEY_new_mac_key: malloc failure')
end
end

context 'when OpenSSL raises any other error' do
before do
allow(OpenSSL::HMAC).to receive(:digest).and_raise(OpenSSL::HMACError.new('Another Random Error'))
end

it 'raises the original error' do
expect { subject }.to raise_error(OpenSSL::HMACError, 'Another Random Error')
end
end

context 'when other versions of openssl do not raise an exception' do
let(:response) { Base64.decode64("iM0hCLU0fZc885zfkFPX3UJwSHbYyam9ji0WglnT3fc=\n") }
before do
allow(OpenSSL::HMAC).to receive(:digest).and_return(response)
end

it { is_expected.to eql(response) }
end
end
end
end

0 comments on commit 6c9dc8f

Please sign in to comment.