nginx
nginx/jwt-lib/resty/hmac.lua
Make nginx kubernetes-ready. We had to update to use a ubuntu-based image to build nginx into, because (and I kid you not) alpine linux straight-up ignores your resolv.conf file, meaning any attempt to use it with kubernetes DNS is doomed to fail. Who thought this was a good idea? So we're using a bloated image instead. Oh well. We also are running a wrapper script instead of nginx directly, so we can inject the JWT_SECRET environment variable based on a kubernetes secret file. We define the secret file (using a placeholder secret, obvs) so that future-Paddy can remember what the hell it looks like, when he inevitably loses the file and needs to sin up a new cluster. Or whatever. Finally, we updated the token expiration error message to be in an errors array, as God (and our API conventions) intended.
| 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 |