Skip to content

Commit

Permalink
Define the secp256r1 curve
Browse files Browse the repository at this point in the history
  • Loading branch information
anakinj committed Dec 12, 2020
1 parent dc946fa commit d4ef694
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 9 deletions.
31 changes: 22 additions & 9 deletions lib/jwt/algos/ecdsa.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,46 @@ module Algos
module Ecdsa
module_function

SUPPORTED = %w[ES256 ES384 ES512].freeze
NAMED_CURVES = {
'prime256v1' => 'ES256',
'secp384r1' => 'ES384',
'secp521r1' => 'ES512'
'secp256r1' => 'ES256', # alias for prime256v1
'secp384r1' => 'ES384',
'secp521r1' => 'ES512'
}.freeze

SUPPORTED = NAMED_CURVES.values.uniq.freeze

def sign(to_sign)
algorithm, msg, key = to_sign.values
key_algorithm = NAMED_CURVES[key.group.curve_name]
if algorithm != key_algorithm
curve_definition = curve_by_name(key.group.curve_name)
if algorithm != curve_definition[:algorithm]
raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} signing key was provided"
end

digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
digest = OpenSSL::Digest.new(curve_definition[:digest])
SecurityUtils.asn1_to_raw(key.dsa_sign_asn1(digest.digest(msg)), key)
end

def verify(to_verify)
algorithm, public_key, signing_input, signature = to_verify.values
key_algorithm = NAMED_CURVES[public_key.group.curve_name]
if algorithm != key_algorithm
curve_definition = curve_by_name(public_key.group.curve_name)
if algorithm != curve_definition[:algorithm]
raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided"
end
digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
digest = OpenSSL::Digest.new(curve_definition[:digest])
public_key.dsa_verify_asn1(digest.digest(signing_input), SecurityUtils.raw_to_asn1(signature, public_key))
end

def curve_by_name(name)
algorithm = NAMED_CURVES.fetch(name) do
raise UnsupportedEcdsaCurve, "The ECDSA curve '#{name}' is not supported"
end

{
algorithm: algorithm,
digest: algorithm.sub('ES', 'sha')
}
end
end
end
end
1 change: 1 addition & 0 deletions lib/jwt/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class ExpiredSignature < DecodeError; end
class IncorrectAlgorithm < DecodeError; end
class ImmatureSignature < DecodeError; end
class InvalidIssuerError < DecodeError; end
class UnsupportedEcdsaCurve < IncorrectAlgorithm; end
class InvalidIatError < DecodeError; end
class InvalidAudError < DecodeError; end
class InvalidSubError < DecodeError; end
Expand Down
27 changes: 27 additions & 0 deletions spec/jwt/algos/ecdsa_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
RSpec.describe ::JWT::Algos::Ecdsa do
describe '.curve_by_name' do
subject { described_class.curve_by_name(curve_name) }

context 'when secp256r1 is given' do
let(:curve_name) { 'secp256r1' }
it { is_expected.to eq(algorithm: 'ES256', digest: 'sha256') }
end

context 'when prime256v1 is given' do
let(:curve_name) { 'prime256v1' }
it { is_expected.to eq(algorithm: 'ES256', digest: 'sha256') }
end

context 'when secp521r1 is given' do
let(:curve_name) { 'secp521r1' }
it { is_expected.to eq(algorithm: 'ES512', digest: 'sha512') }
end

context 'when unkown is given' do
let(:curve_name) { 'unkown' }
it 'raises an error' do
expect { subject }.to raise_error(JWT::UnsupportedEcdsaCurve)
end
end
end
end

0 comments on commit d4ef694

Please sign in to comment.