Skip to content

Commit

Permalink
Correctly sign ecdsa JWTs
Browse files Browse the repository at this point in the history
Fixes #84
  • Loading branch information
jurriaan committed Jun 14, 2015
1 parent f1f5508 commit 6b71cb4
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 2 deletions.
16 changes: 14 additions & 2 deletions lib/jwt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def sign_ecdsa(algorithm, msg, private_key)
end

digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
private_key.dsa_sign_asn1(digest.digest(msg))
asn1_to_raw(private_key.dsa_sign_asn1(digest.digest(msg)), private_key)
end

def verify_rsa(algorithm, public_key, signing_input, signature)
Expand All @@ -66,7 +66,7 @@ def verify_ecdsa(algorithm, public_key, signing_input, signature)
end

digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
public_key.dsa_verify_asn1(digest.digest(signing_input), signature)
public_key.dsa_verify_asn1(digest.digest(signing_input), raw_to_asn1(signature, public_key))
end

def sign_hmac(algorithm, msg, key)
Expand Down Expand Up @@ -218,4 +218,16 @@ def secure_compare(a, b)
b.each_byte { |byte| res |= byte ^ l.shift }
res == 0
end

def raw_to_asn1(signature, private_key)
byte_size = (private_key.group.degree / 8.0).ceil
r = signature[0..(byte_size - 1)]
s = signature[byte_size..-1]
OpenSSL::ASN1::Sequence.new([r, s].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
end

def asn1_to_raw(signature, public_key)
byte_size = (public_key.group.degree / 8.0).ceil
OpenSSL::ASN1.decode(signature).value.map { |value| value.value.to_s(2).rjust(byte_size, "\x00") }.join
end
end
9 changes: 9 additions & 0 deletions spec/jwt_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@
expect(decoded_payload).to include(example_payload)
end

it 'decodes valid ES512 JWTs' do
example_payload = { 'hello' => 'world' }
example_jwt = 'eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIn0.AQx1MqdTni6KuzfOoedg2-7NUiwe-b88SWbdmviz40GTwrM0Mybp1i1tVtmTSQ91oEXGXBdtwsN6yalzP9J-sp2YATX_Tv4h-BednbdSvYxZsYnUoZ--ZUdL10t7g8Yt3y9hdY_diOjIptcha6ajX8yzkDGYG42iSe3f5LywSuD6FO5c'
pubkey_pem = "-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAcpkss6wI7PPlxj3t7A1RqMH3nvL4\nL5Tzxze/XeeYZnHqxiX+gle70DlGRMqqOq+PJ6RYX7vK0PJFdiAIXlyPQq0B3KaU\ne86IvFeQSFrJdCc0K8NfiH2G1loIk3fiR+YLqlXk6FAeKtpXJKxR1pCQCAM+vBCs\nmZudf1zCUZ8/4eodlHU=\n-----END PUBLIC KEY-----"
pubkey = OpenSSL::PKey::EC.new pubkey_pem
decoded_payload = JWT.decode(example_jwt, pubkey)
expect(decoded_payload).to include(example_payload)
end

it 'decodes valid JWTs with iss' do
example_payload = { 'hello' => 'world', 'iss' => 'jwtiss' }
example_secret = 'secret'
Expand Down

0 comments on commit 6b71cb4

Please sign in to comment.