nginx
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.
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