nov/json-jwt

verify signature JWT

ErnstA opened this issue · 4 comments

I have a JWT

"eyJhbGciOiJSUzI1Ni..."

I can get the public key as a Ruby hash:

{"use"=>"sig",
 "kty"=>"RSA",
 "kid"=>"public",
 "n"=>
  "usTrcR3PIAKm37Q1...",
 "e"=>"AQAB"}
JSON::JWT.decode jwt, :skip_verification
=> {"aud"=>"e0172bf8-9d09-4ed8-b8ac-b1d07b43ae77",
 "exp"=>1487993654,
 "jti"=>"131bc753-bdd9-40e3-901c-a80a61240740",
 "redir"=> "https://test.....org/oauth2/auth?client_id=e01....",
 "scp"=>["hydra", "offline", "openid"]
}

BUT

jwk2 = JSON::JWK.new jwk
JSON::JWT.decode jwt , jwk2
ArgumentError: wrong number of arguments (given 0, expected 1)
from /home/ernst/.rvm/gems/ruby-2.3.0@rails5.0.0.1_students/gems/keystores-0.2.0/lib/keystores/jks/pkcs8_key.rb:63:in `block in <class:RSA>'

BTW
How to convert the key

{"use"=>"sig",
 "kty"=>"RSA",
 "kid"=>"public",
 "n"=>
  "usTrcR3PIAKm37Q1...",
 "e"=>"AQAB"}

to PEM format? Either in Ruby or if that is not available on the Linux command line.

nov commented

This code works fine, so I have no idea what's wrong on your side.
See your code around line#63 of "pkcs8_key.rb".

For PEM generation, you can get OpenSSL::PKey::RSA instance by calling JSON::JWK#to_key, so that you can get PEMized JWK by calling jwk.to_key.to_pem.

require 'json/jwt'

private_key = OpenSSL::PKey::RSA.generate 2048

public_jwk = JSON::JWK.new private_key.public_key

puts <<-JWK
# Public JWK
#{JSON.pretty_generate public_jwk}

JWK

jwt_claims = {
  foo: :bar
}
plain_jwt = JSON::JWT.new jwt_claims
signed_jwt = plain_jwt.sign private_key
jwt_string = signed_jwt.to_s

puts <<-JWT
# JWT String
#{jwt_string}

JWT

decoded_jwt = JSON::JWT.decode jwt_string, public_jwk

puts <<-JWT
# Decoded JWT

## Header
#{JSON.pretty_generate decoded_jwt.header}

## Payload
#{JSON.pretty_generate decoded_jwt}

JWT

pemized_jwk = public_jwk.to_key.to_pem

puts <<-PEM
# PEMized JWK
#{pemized_jwk}
PEM

Thanks Nov, I run your example from above in an Rspec test and it fails here:

> decoded_jwt = JSON::JWT.decode jwt_string, public_jwk
ArgumentError: wrong number of arguments (given 0, expected 1)
from /home/ernst/.rvm/gems/ruby-2.3.0@rails5.0.0.1_students/gems/keystores-0.2.0/lib/keystores/jks/pkcs8_key.rb:63:in `block in <class:RSA>'

versions: ruby-2.3.0@rails5.0.0.1

pkcs8_key.rb:63

    class RSA
      original_initialize = instance_method(:initialize)

      define_method(:initialize) do |der_or_pem|   # line 63
        init = original_initialize.bind(self)
        begin
          init.(der_or_pem)
        rescue Exception

RSA.new does not get a parameter

keystores-0.2.0/lib/keystores/jks/pkcs8_key.rb:63:in `block in <class:RSA>'
    json-jwt-1.6.5/lib/json/jwk.rb:98:in `new'
    json-jwt-1.6.5/lib/json/jwk.rb:98:in `to_rsa_key'
    json-jwt-1.6.5/lib/json/jwk.rb:43:in `to_key'
    json-jwt-1.6.5/lib/json/jose.rb:26:in `with_jwk_support'
    json-jwt-1.6.5/lib/json/jws.rb:88:in `valid?'
    json-jwt-1.6.5/lib/json/jws.rb:25:in `verify!'
    json-jwt-1.6.5/lib/json/jws.rb:149:in `decode_compact_serialized'
    json-jwt-1.6.5/lib/json/jwt.rb:86:in `decode_compact_serialized'
    json-jwt-1.6.5/lib/json/jose.rb:52:in `decode

json-jwt-1.6.5/lib/json/jwk.rb

    def to_rsa_key
      e, n, d, p, q = [:e, :n, :d, :p, :q].collect do |key|
        if self[key]
          OpenSSL::BN.new UrlSafeBase64.decode64(self[key]), 2
        end
      end
      key = OpenSSL::PKey::RSA.new              # line 98
      key.e = e
      key.n = n

seems there is some incompatibility in the libraries I use.

Now it works. I had in my Gemfile

gem 'keystores' # https://github.com/rylarson/keystores

After removing that gem it works.