Class: JWT::JWA::Ecdsa

Inherits:
Object
  • Object
show all
Includes:
SigningAlgorithm
Defined in:
lib/jwt/jwa/ecdsa.rb

Overview

ECDSA signing algorithm

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

Instance Attribute Summary

Attributes included from SigningAlgorithm

#alg

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SigningAlgorithm

#header, #raise_sign_error!, #raise_verify_error!, #valid_alg?

Constructor Details

#initialize(alg, digest) ⇒ Ecdsa

Returns a new instance of Ecdsa.



9
10
11
12
# File 'lib/jwt/jwa/ecdsa.rb', line 9

def initialize(alg, digest)
  @alg = alg
  @digest = OpenSSL::Digest.new(digest)
end

Class Method Details

.create_public_key_from_point(point) ⇒ Object



75
76
77
78
79
80
81
# File 'lib/jwt/jwa/ecdsa.rb', line 75

def self.create_public_key_from_point(point)
  sequence = OpenSSL::ASN1::Sequence([
                                       OpenSSL::ASN1::Sequence([OpenSSL::ASN1::ObjectId('id-ecPublicKey'), OpenSSL::ASN1::ObjectId(point.group.curve_name)]),
                                       OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed))
                                     ])
  OpenSSL::PKey::EC.new(sequence.to_der)
end

.curve_by_name(name) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



68
69
70
71
72
# File 'lib/jwt/jwa/ecdsa.rb', line 68

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

Instance Method Details

#sign(data:, signing_key:) ⇒ Object

Raises:



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/jwt/jwa/ecdsa.rb', line 14

def sign(data:, signing_key:)
  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)
  raise_sign_error!('The given key is not a private key') unless signing_key.private?

  curve_definition = curve_by_name(signing_key.group.curve_name)
  key_algorithm = curve_definition[:algorithm]

  raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} signing key was provided" if alg != key_algorithm

  asn1_to_raw(signing_key.dsa_sign_asn1(digest.digest(data)), signing_key)
end

#verify(data:, signature:, verification_key:) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/jwt/jwa/ecdsa.rb', line 26

def verify(data:, signature:, verification_key:)
  verification_key = self.class.create_public_key_from_point(verification_key) if verification_key.is_a?(::OpenSSL::PKey::EC::Point)

  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)

  curve_definition = curve_by_name(verification_key.group.curve_name)
  key_algorithm = curve_definition[:algorithm]
  raise IncorrectAlgorithm, "payload algorithm is #{alg} but #{key_algorithm} verification key was provided" if alg != key_algorithm

  verification_key.dsa_verify_asn1(digest.digest(data), raw_to_asn1(signature, verification_key))
rescue OpenSSL::PKey::PKeyError
  raise JWT::VerificationError, 'Signature verification raised'
end