Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help implementing new JWT token validation feature to the lbrary #71

Closed
venkatmarepalli opened this issue Jun 19, 2017 · 3 comments
Closed

Comments

@venkatmarepalli
Copy link

Can someone add this functionality to this library. This will make this library to work for tokens which don't have x5c entry #34 . Function to convert public key to pem.

@venkatmarepalli
Copy link
Author

I am trying to implement this functionality. I was able to write the entire code but the public key that is generated in not validating the signature using jwt.io. Can some one take a look at this code and point me what was the mistake. I feel that I have to add some headers to the pem key

The final Pem key differs slightly by a bit. I guess I am missing something. Here is the difference in the keys that I see. There is an extra MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A in the GoLang method.Can someone point me what I am missing

My Key generated by the lua code
------------BEGIN PUBLIC KEY-----
MIIBCgKCAQEAtVKUtcx/n9rt5afY/2WFNvU6PlFMggCatsZ3l4RjKxH0jgdLq6CS
cb0P3ZGXYbPzXvmmLiWZizpb+h0

Key generated by GoLang.
------------BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtVKUtcx/n9rt5afY/2WF
NvU6PlFMggCatsZ3l4RjKxH0jgdLq6CScb0P3ZGXYbPzXvmmLiWZizpb+h0qup5j

The Code that I implemented. I guess OID is the issue, I think I have to get the ASN.1 for pcks(1) and update the OID with this value, I am not sure how I can get this. http://oid-info.com/get/1.2.840.113549.1.1.1

local b64     = ngx.encode_base64
local unb64   = ngx.decode_base64

-- Base64url decode
local b64map = { ['-'] = '+', ['_'] = '/' };
local function unb64url(s)
    return (unb64(s:gsub("[-_]", b64map) .. "=="));
end

local function get_rsa_publickey(kid,jwks)
  local n = get_jwk(jwks.keys,kid).n
  local e = get_jwk(jwks.keys,kid).e
  if e == "AQAB" or e == "AAEAAQ" then
        e = 65537
  end
  local kty = get_jwk(jwks.keys,kid).kty
  return n, e, kty
end

--Main routine to retrieve pem from jwks
local function pem_from_jwk (opts, kid)
  local jwks, err = openidc_jwks(opts.discovery.jwks_uri, opts.ssl_verify)
  if err then
    return nil, err
  end

  local n, e, kty = get_rsa_publickey(kid,jwks)
  ngx.log(ngx.DEBUG,"-------n------>",n)
  ngx.log(ngx.DEBUG,"-------e------>",e)
  ngx.log(ngx.DEBUG,"-------kty---->",kty)
  local der_key = {}
  table.insert(der_key, unb64url(get_jwk(jwks.keys,kid).n));
  if e == "AQAB" or e == "AAEAAQ" then
        e = 65537
  end

  table.insert(der_key, unb64url(get_jwk(jwks.keys,kid).e));

  for k,v in pairs(der_key)
        do ngx.log(ngx.DEBUG,"----->",k,"----",v)
   end
  local encoded_key = encode_sequence_of_integer(der_key);
  ngx.log(ngx.DEBUG,"---------encoded key------->", encoded_key)

  ngx.log(ngx.DEBUG,"-----dertopem--------->",der2pem(encoded_key, kty .. " PRIVATE KEY"))
end

local wrap = ('.'):rep(64);
local envelope = "-----BEGIN %s-----\n%s\n-----END %s-----\n"

local function der2pem(data, typ)
    typ = typ and typ:upper() or "CERTIFICATE";
    data = b64(data);
    return string.format(envelope, typ, data:gsub(wrap, '%0\n', (#data-1)/64), typ);
end

local function encode_length(length)
    if length < 0x80 then
        return string.char(length);
    elseif length < 0x100 then
        return string.char(0x81, length);
    elseif length < 0x10000 then
        return string.char(0x82, math.floor(length/0x100), length%0x100);
    end
    error("Can't encode lengths over 65535");
end

local function encode_sequence(array, of)
    local encoded_array = array;
    if of then
        encoded_array = {};
        for i = 1, #array do
            encoded_array[i] = of(array[i]);
        end
    end
    encoded_array = table.concat(encoded_array);

    return string.char(0x30) .. encode_length(#encoded_array) .. encoded_array;
end

local function encode_binary_integer(bytes)
    if bytes:byte(1) > 128 then
        ngx.log(ngx.DEBUG,"---------byte>128------->")
        -- We currenly only use this for unsigned integers,
        -- however since the high bit is set here, it would look
        -- like a negative signed int, so prefix with zeroes
        bytes = "\0" .. bytes;
     end
        ngx.log(ngx.DEBUG,"------returning from encode binary integer------>",bytes)
     return "\2" .. encode_length(#bytes) .. bytes;
end

local function encode_sequence_of_integer(array)
        return encode_sequence(array,encode_binary_integer);
end

Reference: https://www.zash.se/jwk2pem.lua.html

@zandbelt
Copy link
Contributor

zandbelt commented Oct 5, 2017

I've started to include this and use it for OIDC id_token validation as well in this branch: https://github.com/pingidentity/lua-resty-openidc/tree/support-rsa-kty-jwks

@venkatmarepalli
Copy link
Author

Please take a look at this discussion, this might help

SkyLothar/lua-resty-jwt#66 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants