Module: JWT::Algos::Ecdsa

Defined in:
lib/jwt/algos/ecdsa.rb

Constant Summary collapse

NAMED_CURVES =
{
  'prime256v1' => {
    algorithm: 'ES256',
    digest: 'sha256'
  },
  'secp256r1' => { # alias for prime256v1
    algorithm: 'ES256',
    digest: 'sha256'
  },
  'secp384r1' => {
    algorithm: 'ES384',
    digest: 'sha384'
  },
  'secp521r1' => {
    algorithm: 'ES512',
    digest: 'sha512'
  },
  'secp256k1' => {
    algorithm: 'ES256K',
    digest: 'sha256'
  }
}.freeze
SUPPORTED =
NAMED_CURVES.map { |_, c| c[:algorithm] }.uniq.freeze

Class Method Summary collapse

Class Method Details

.asn1_to_raw(signature, public_key) ⇒ Object



70
71
72
73
# File 'lib/jwt/algos/ecdsa.rb', line 70

def asn1_to_raw(signature, public_key)
  byte_size = (public_key.group.degree + 7) / 8
  OpenSSL::ASN1.decode(signature).value.map { |value| value.value.to_s(2).rjust(byte_size, "\x00") }.join
end

.curve_by_name(name) ⇒ Object



57
58
59
60
61
# File 'lib/jwt/algos/ecdsa.rb', line 57

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

.raw_to_asn1(signature, private_key) ⇒ Object



63
64
65
66
67
68
# File 'lib/jwt/algos/ecdsa.rb', line 63

def raw_to_asn1(signature, private_key)
  byte_size = (private_key.group.degree + 7) / 8
  sig_bytes = signature[0..(byte_size - 1)]
  sig_char = signature[byte_size..-1] || ''
  OpenSSL::ASN1::Sequence.new([sig_bytes, sig_char].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
end

.sign(algorithm, msg, key) ⇒ Object



33
34
35
36
37
38
39
40
41
42
# File 'lib/jwt/algos/ecdsa.rb', line 33

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

  digest = OpenSSL::Digest.new(curve_definition[:digest])
  asn1_to_raw(key.dsa_sign_asn1(digest.digest(msg)), key)
end

.verify(algorithm, public_key, signing_input, signature) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/jwt/algos/ecdsa.rb', line 44

def verify(algorithm, public_key, signing_input, signature)
  curve_definition = curve_by_name(public_key.group.curve_name)
  key_algorithm = curve_definition[:algorithm]
  if algorithm != key_algorithm
    raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided"
  end

  digest = OpenSSL::Digest.new(curve_definition[:digest])
  public_key.dsa_verify_asn1(digest.digest(signing_input), raw_to_asn1(signature, public_key))
rescue OpenSSL::PKey::PKeyError
  raise JWT::VerificationError, 'Signature verification raised'
end