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
paddy@0 1
paddy@0 2 local str_util = require "resty.string"
paddy@0 3 local ffi = require "ffi"
paddy@0 4 local ffi_new = ffi.new
paddy@0 5 local ffi_str = ffi.string
paddy@0 6 local ffi_gc = ffi.gc
paddy@0 7 local C = ffi.C
paddy@0 8 local setmetatable = setmetatable
paddy@0 9 local error = error
paddy@0 10
paddy@0 11
paddy@0 12 local _M = { _VERSION = '0.01' }
paddy@0 13
paddy@0 14 local mt = { __index = _M }
paddy@0 15
paddy@0 16
paddy@0 17 ffi.cdef[[
paddy@0 18 typedef struct engine_st ENGINE;
paddy@0 19 typedef struct evp_pkey_ctx_st EVP_PKEY_CTX;
paddy@0 20 typedef struct env_md_ctx_st EVP_MD_CTX;
paddy@0 21 typedef struct env_md_st EVP_MD;
paddy@0 22
paddy@0 23 struct env_md_ctx_st
paddy@0 24 {
paddy@0 25 const EVP_MD *digest;
paddy@0 26 ENGINE *engine;
paddy@0 27 unsigned long flags;
paddy@0 28 void *md_data;
paddy@0 29 EVP_PKEY_CTX *pctx;
paddy@0 30 int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count);
paddy@0 31 };
paddy@0 32
paddy@0 33 struct env_md_st
paddy@0 34 {
paddy@0 35 int type;
paddy@0 36 int pkey_type;
paddy@0 37 int md_size;
paddy@0 38 unsigned long flags;
paddy@0 39 int (*init)(EVP_MD_CTX *ctx);
paddy@0 40 int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count);
paddy@0 41 int (*final)(EVP_MD_CTX *ctx,unsigned char *md);
paddy@0 42 int (*copy)(EVP_MD_CTX *to,const EVP_MD_CTX *from);
paddy@0 43 int (*cleanup)(EVP_MD_CTX *ctx);
paddy@0 44
paddy@0 45 int (*sign)(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, void *key);
paddy@0 46 int (*verify)(int type, const unsigned char *m, unsigned int m_length, const unsigned char *sigbuf, unsigned int siglen, void *key);
paddy@0 47 int required_pkey_type[5];
paddy@0 48 int block_size;
paddy@0 49 int ctx_size;
paddy@0 50 int (*md_ctrl)(EVP_MD_CTX *ctx, int cmd, int p1, void *p2);
paddy@0 51 };
paddy@0 52
paddy@0 53 typedef struct hmac_ctx_st
paddy@0 54 {
paddy@0 55 const EVP_MD *md;
paddy@0 56 EVP_MD_CTX md_ctx;
paddy@0 57 EVP_MD_CTX i_ctx;
paddy@0 58 EVP_MD_CTX o_ctx;
paddy@0 59 unsigned int key_length;
paddy@0 60 unsigned char key[128];
paddy@0 61 } HMAC_CTX;
paddy@0 62
paddy@0 63 void HMAC_CTX_init(HMAC_CTX *ctx);
paddy@0 64 void HMAC_CTX_cleanup(HMAC_CTX *ctx);
paddy@0 65
paddy@0 66 int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len,const EVP_MD *md, ENGINE *impl);
paddy@0 67 int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len);
paddy@0 68 int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len);
paddy@0 69
paddy@0 70 const EVP_MD *EVP_md5(void);
paddy@0 71 const EVP_MD *EVP_sha1(void);
paddy@0 72 const EVP_MD *EVP_sha256(void);
paddy@0 73 const EVP_MD *EVP_sha512(void);
paddy@0 74 ]]
paddy@0 75
paddy@0 76 local buf = ffi_new("unsigned char[64]")
paddy@0 77 local res_len = ffi_new("unsigned int[1]")
paddy@0 78 local ctx_ptr_type = ffi.typeof("HMAC_CTX[1]")
paddy@0 79 local hashes = {
paddy@0 80 MD5 = C.EVP_md5(),
paddy@0 81 SHA1 = C.EVP_sha1(),
paddy@0 82 SHA256 = C.EVP_sha256(),
paddy@0 83 SHA512 = C.EVP_sha512()
paddy@0 84 }
paddy@0 85
paddy@0 86
paddy@0 87 _M.ALGOS = hashes
paddy@0 88
paddy@0 89
paddy@0 90 function _M.new(self, key, hash_algo)
paddy@0 91 local ctx = ffi_new(ctx_ptr_type)
paddy@0 92
paddy@0 93 C.HMAC_CTX_init(ctx)
paddy@0 94
paddy@0 95 local _hash_algo = hash_algo or hashes.md5
paddy@0 96
paddy@0 97 if C.HMAC_Init_ex(ctx, key, #key, _hash_algo, nil) == 0 then
paddy@0 98 return nil
paddy@0 99 end
paddy@0 100
paddy@0 101 ffi_gc(ctx, C.HMAC_CTX_cleanup)
paddy@0 102
paddy@0 103 return setmetatable({ _ctx = ctx }, mt)
paddy@0 104 end
paddy@0 105
paddy@0 106
paddy@0 107 function _M.update(self, s)
paddy@0 108 return C.HMAC_Update(self._ctx, s, #s) == 1
paddy@0 109 end
paddy@0 110
paddy@0 111
paddy@0 112 function _M.final(self, s, hex_output)
paddy@0 113
paddy@0 114 if s ~= nil then
paddy@0 115 if C.HMAC_Update(self._ctx, s, #s) == 0 then
paddy@0 116 return nil
paddy@0 117 end
paddy@0 118 end
paddy@0 119
paddy@0 120 if C.HMAC_Final(self._ctx, buf, res_len) == 1 then
paddy@0 121 if hex_output == true then
paddy@0 122 return str_util.to_hex(ffi_str(buf, res_len[0]))
paddy@0 123 end
paddy@0 124 return ffi_str(buf, res_len[0])
paddy@0 125 end
paddy@0 126
paddy@0 127 return nil
paddy@0 128 end
paddy@0 129
paddy@0 130
paddy@0 131 function _M.reset(self)
paddy@0 132 return C.HMAC_Init_ex(self._ctx, nil, 0, nil, nil) == 1
paddy@0 133 end
paddy@0 134
paddy@0 135 return _M