nginx

Paddy 2015-06-22

0:68478c1bddde Go to Latest

nginx/jwt-lib/resty/hmac.lua

First basic pass at JWT auth. Mostly just a fork of https://github.com/ficusio/openresty, with a few twists: * We've narrowed down some of the configuration options, and we're passing more headers (essentially exposing all the data in the JWT as headers). * We no longer automatically return a 401 unauthorized if the JWT verification fails; we just don't assign it the headers. The consuming service can decide whether or not they want to accept the request. * We automatically fail the verification of a JWT if the token has expired in the last minute (or shouldn't be used for the next minute). If the token has expired, we return a 401 that our clients can catch and use a refresh token automatically from. If the token can't be used for another minute, we quietly just refuse to add auth headers to the request.

History
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/jwt-lib/resty/hmac.lua	Mon Jun 22 00:42:40 2015 -0400
     1.3 @@ -0,0 +1,135 @@
     1.4 +
     1.5 +local str_util = require "resty.string"
     1.6 +local ffi = require "ffi"
     1.7 +local ffi_new = ffi.new
     1.8 +local ffi_str = ffi.string
     1.9 +local ffi_gc = ffi.gc
    1.10 +local C = ffi.C
    1.11 +local setmetatable = setmetatable
    1.12 +local error = error
    1.13 +
    1.14 +
    1.15 +local _M = { _VERSION = '0.01' }
    1.16 +
    1.17 +local mt = { __index = _M }
    1.18 +
    1.19 +
    1.20 +ffi.cdef[[
    1.21 +typedef struct engine_st ENGINE;
    1.22 +typedef struct evp_pkey_ctx_st EVP_PKEY_CTX;
    1.23 +typedef struct env_md_ctx_st EVP_MD_CTX;
    1.24 +typedef struct env_md_st EVP_MD;
    1.25 +
    1.26 +struct env_md_ctx_st
    1.27 +    {
    1.28 +    const EVP_MD *digest;
    1.29 +    ENGINE *engine;
    1.30 +    unsigned long flags;
    1.31 +    void *md_data;
    1.32 +    EVP_PKEY_CTX *pctx;
    1.33 +    int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count);
    1.34 +    };
    1.35 +
    1.36 +struct env_md_st
    1.37 +    {
    1.38 +    int type;
    1.39 +    int pkey_type;
    1.40 +    int md_size;
    1.41 +    unsigned long flags;
    1.42 +    int (*init)(EVP_MD_CTX *ctx);
    1.43 +    int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count);
    1.44 +    int (*final)(EVP_MD_CTX *ctx,unsigned char *md);
    1.45 +    int (*copy)(EVP_MD_CTX *to,const EVP_MD_CTX *from);
    1.46 +    int (*cleanup)(EVP_MD_CTX *ctx);
    1.47 +
    1.48 +    int (*sign)(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, void *key);
    1.49 +    int (*verify)(int type, const unsigned char *m, unsigned int m_length, const unsigned char *sigbuf, unsigned int siglen, void *key);
    1.50 +    int required_pkey_type[5];
    1.51 +    int block_size;
    1.52 +    int ctx_size;
    1.53 +    int (*md_ctrl)(EVP_MD_CTX *ctx, int cmd, int p1, void *p2);
    1.54 +    };
    1.55 +
    1.56 +typedef struct hmac_ctx_st
    1.57 +    {
    1.58 +    const EVP_MD *md;
    1.59 +    EVP_MD_CTX md_ctx;
    1.60 +    EVP_MD_CTX i_ctx;
    1.61 +    EVP_MD_CTX o_ctx;
    1.62 +    unsigned int key_length;
    1.63 +    unsigned char key[128];
    1.64 +    } HMAC_CTX;
    1.65 +
    1.66 +void HMAC_CTX_init(HMAC_CTX *ctx);
    1.67 +void HMAC_CTX_cleanup(HMAC_CTX *ctx);
    1.68 +
    1.69 +int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len,const EVP_MD *md, ENGINE *impl);
    1.70 +int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len);
    1.71 +int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len);
    1.72 +
    1.73 +const EVP_MD *EVP_md5(void);
    1.74 +const EVP_MD *EVP_sha1(void);
    1.75 +const EVP_MD *EVP_sha256(void);
    1.76 +const EVP_MD *EVP_sha512(void);
    1.77 +]]
    1.78 +
    1.79 +local buf = ffi_new("unsigned char[64]")
    1.80 +local res_len = ffi_new("unsigned int[1]")
    1.81 +local ctx_ptr_type = ffi.typeof("HMAC_CTX[1]")
    1.82 +local hashes = {
    1.83 +    MD5 = C.EVP_md5(),
    1.84 +    SHA1 = C.EVP_sha1(),
    1.85 +    SHA256 = C.EVP_sha256(),
    1.86 +    SHA512 = C.EVP_sha512()
    1.87 +}
    1.88 +
    1.89 +
    1.90 +_M.ALGOS = hashes
    1.91 +
    1.92 +
    1.93 +function _M.new(self, key, hash_algo)
    1.94 +    local ctx = ffi_new(ctx_ptr_type)
    1.95 +
    1.96 +    C.HMAC_CTX_init(ctx)
    1.97 +
    1.98 +    local _hash_algo = hash_algo or hashes.md5
    1.99 +
   1.100 +    if C.HMAC_Init_ex(ctx, key, #key, _hash_algo, nil) == 0 then
   1.101 +        return nil
   1.102 +    end
   1.103 +
   1.104 +    ffi_gc(ctx, C.HMAC_CTX_cleanup)
   1.105 +
   1.106 +    return setmetatable({ _ctx = ctx }, mt)
   1.107 +end
   1.108 +
   1.109 +
   1.110 +function _M.update(self, s)
   1.111 +    return C.HMAC_Update(self._ctx, s, #s) == 1
   1.112 +end
   1.113 +
   1.114 +
   1.115 +function _M.final(self, s, hex_output)
   1.116 +
   1.117 +    if s ~= nil then
   1.118 +        if C.HMAC_Update(self._ctx, s, #s) == 0 then
   1.119 +            return nil
   1.120 +        end
   1.121 +    end
   1.122 +
   1.123 +    if C.HMAC_Final(self._ctx, buf, res_len) == 1 then
   1.124 +        if hex_output == true then
   1.125 +            return str_util.to_hex(ffi_str(buf, res_len[0]))
   1.126 +        end
   1.127 +        return ffi_str(buf, res_len[0])
   1.128 +    end
   1.129 +
   1.130 +    return nil
   1.131 +end
   1.132 +
   1.133 +
   1.134 +function _M.reset(self)
   1.135 +    return C.HMAC_Init_ex(self._ctx, nil, 0, nil, nil) == 1
   1.136 +end
   1.137 +
   1.138 +return _M