Meet SourceLevel, your automatic code reviewer

SourceLevel does continuous static analysis of your GitHub repositories and delivers it straight to your Pull Requests

Get started for free

Great, lib/jwt/jwk/ec.rb does not have any issues!

Go to line 1
# frozen_string_literal: true
Go to line 3
module JWT
Go to line 4
  module JWK
Go to line 5
    class EC < KeyBase
Go to line 6
      extend Forwardable
Go to line 7
      def_delegators :@keypair, :public_key
Go to line 9
      KTY    = 'EC'.freeze
Go to line 10
      KTYS   = [KTY, OpenSSL::PKey::EC].freeze
Go to line 11
      BINARY = 2
Go to line 13
      def initialize(keypair, kid = nil)
Go to line 14
        raise ArgumentError, 'keypair must be of type OpenSSL::PKey::EC' unless keypair.is_a?(OpenSSL::PKey::EC)
Go to line 16
        kid ||= generate_kid(keypair)
Go to line 17
        super(keypair, kid)
Go to line 20
      def private?
Go to line 21
        @keypair.private_key?
Go to line 24
      def export(options = {})
Go to line 25
        crv, x_octets, y_octets = keypair_components(keypair)
Go to line 26
        exported_hash = {
Go to line 27
          kty: KTY,
Go to line 28
          crv: crv,
Go to line 29
          x: encode_octets(x_octets),
Go to line 30
          y: encode_octets(y_octets),
Go to line 33
        return exported_hash unless private? && options[:include_private] == true
Go to line 35
        append_private_parts(exported_hash)
Go to line 40
      def append_private_parts(the_hash)
Go to line 41
        octets = keypair.private_key.to_bn.to_s(BINARY)
Go to line 42
        the_hash.merge(
Go to line 43
          d: encode_octets(octets)
Go to line 47
      def generate_kid(ec_keypair)
Go to line 48
        _crv, x_octets, y_octets = keypair_components(ec_keypair)
Go to line 49
        sequence = OpenSSL::ASN1::Sequence([OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(x_octets, BINARY)),
Go to line 50
                                            OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(y_octets, BINARY))])
Go to line 51
        OpenSSL::Digest::SHA256.hexdigest(sequence.to_der)
Go to line 54
      def keypair_components(ec_keypair)
Go to line 55
        encoded_point = ec_keypair.public_key.to_bn.to_s(BINARY)
Go to line 56
        case ec_keypair.group.curve_name
Go to line 57
        when 'prime256v1'
Go to line 58
          crv = 'P-256'
Go to line 59
          x_octets, y_octets = encoded_point.unpack('xa32a32')
Go to line 60
        when 'secp384r1'
Go to line 61
          crv = 'P-384'
Go to line 62
          x_octets, y_octets = encoded_point.unpack('xa48a48')
Go to line 63
        when 'secp521r1'
Go to line 64
          crv = 'P-521'
Go to line 65
          x_octets, y_octets = encoded_point.unpack('xa66a66')
Go to line 67
          raise Jwt::JWKError, "Unsupported curve '#{ec_keypair.group.curve_name}'"
Go to line 69
        [crv, x_octets, y_octets]
Go to line 72
      def encode_octets(octets)
Go to line 73
        ::JWT::Base64.url_encode(octets)
Go to line 76
      def encode_open_ssl_bn(key_part)
Go to line 77
        ::JWT::Base64.url_encode(key_part.to_s(BINARY))
Go to line 80
      class << self
Go to line 81
        def import(jwk_data)
Go to line 82
          # See https://tools.ietf.org/html/rfc7518#section-6.2.1 for an
Go to line 83
          # explanation of the relevant parameters.
Go to line 85
          jwk_crv, jwk_x, jwk_y, jwk_d, jwk_kid = jwk_attrs(jwk_data, %i[crv x y d kid])
Go to line 86
          raise Jwt::JWKError, 'Key format is invalid for EC' unless jwk_crv && jwk_x && jwk_y
Go to line 88
          new(ec_pkey(jwk_crv, jwk_x, jwk_y, jwk_d), jwk_kid)
Go to line 91
        def to_openssl_curve(crv)
Go to line 92
          # The JWK specs and OpenSSL use different names for the same curves.
Go to line 93
          # See https://tools.ietf.org/html/rfc5480#section-2.1.1.1 for some
Go to line 94
          # pointers on different names for common curves.
Go to line 96
          when 'P-256' then 'prime256v1'
Go to line 97
          when 'P-384' then 'secp384r1'
Go to line 98
          when 'P-521' then 'secp521r1'
Go to line 99
          else raise JWT::JWKError, 'Invalid curve provided'
Go to line 105
        def jwk_attrs(jwk_data, attrs)
Go to line 106
          attrs.map do |attr|
Go to line 107
            jwk_data[attr] || jwk_data[attr.to_s]
Go to line 111
        def ec_pkey(jwk_crv, jwk_x, jwk_y, jwk_d)
Go to line 112
          curve = to_openssl_curve(jwk_crv)
Go to line 114
          x_octets = decode_octets(jwk_x)
Go to line 115
          y_octets = decode_octets(jwk_y)
Go to line 117
          key = OpenSSL::PKey::EC.new(curve)
Go to line 119
          # The details of the `Point` instantiation are covered in:
Go to line 120
          # - https://docs.ruby-lang.org/en/2.4.0/OpenSSL/PKey/EC.html
Go to line 121
          # - https://www.openssl.org/docs/manmaster/man3/EC_POINT_new.html
Go to line 122
          # - https://tools.ietf.org/html/rfc5480#section-2.2
Go to line 123
          # - https://www.secg.org/SEC1-Ver-1.0.pdf
Go to line 124
          # Section 2.3.3 of the last of these references specifies that the
Go to line 125
          # encoding of an uncompressed point consists of the byte `0x04` followed
Go to line 126
          # by the x value then the y value.
Go to line 127
          point = OpenSSL::PKey::EC::Point.new(
Go to line 128
            OpenSSL::PKey::EC::Group.new(curve),
Go to line 129
            OpenSSL::BN.new([0x04, x_octets, y_octets].pack('Ca*a*'), 2)
Go to line 132
          key.public_key = point
Go to line 133
          key.private_key = OpenSSL::BN.new(decode_octets(jwk_d), 2) if jwk_d
Go to line 138
        def decode_octets(jwk_data)
Go to line 139
          ::JWT::Base64.url_decode(jwk_data)
Go to line 142
        def decode_open_ssl_bn(jwk_data)
Go to line 143
          OpenSSL::BN.new(::JWT::Base64.url_decode(jwk_data), BINARY)